本文已参与「新人创作礼」活动,一起开启掘金创作之路。
2022杭电多校六 1006-Maex (树形DP)
样例输入:
3
5
1 2
3 2
1 5
4 1
3
1 2
2 3
1
样例输出:
8
6
1
题意:给你一个n个节点的有根树,根节点是1,我们可以给n个节点每个节点一个权值,但是任意两个节点的权值是不能相同的,定义bi为以第i个节点为根的子树中所有节点权值的mex值,的问我们bi和的最大值。
因为每个节点的权值必须两两不同,0只能在某个子树内,所以除了这个子树之外的其他节点所对应的b一定为0,所以我们可以尽可能让这棵子树之内的所有点的权值尽可能连续,那么我们根节点的b值就大。我们可以令f[i]表示以i节点为根的子树中所有节点的mex之和最大值是多少,再用一个cnt[i]记录以i节点为根的子树中所有节点的个数是多少,那么我们直接进行动态转移即可:f[u]=cnt[u]+max(f[v])其中v是u的子节点。
细节见代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
const int N=5e6+10;
int e[N],ne[N],h[N],idx;
int cnt[N];
long long f[N];//f[i]记录以i节点为根的子树中所有节点的mex之和的最大值
void add(int x,int y)
{
e[idx]=y;
ne[idx]=h[x];
h[x]=idx++;
}
void dfs(int x,int fa)
{
cnt[x]=1;
long long t=0;//记录子节点贡献最大值
for(int i=h[x];i!=-1;i=ne[i])
{
int j=e[i];
if(j==fa) continue;
dfs(j,x);
cnt[x]+=cnt[j];
t=max(f[j],t);
}
f[x]=cnt[x]+t;
}
int main()
{
int T;
cin>>T;
while(T--)
{
idx=0;
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) h[i]=-1;
int u,v;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
dfs(1,-1);
printf("%lld\n",f[1]);
}
return 0;
}
2022杭电多校六 1010-Planar graph(最小生成树)
题意:给n个点和m条边,m条边将一个图分成若干个连通区域,然后我们可以删除一些边,问至少删除多少条边才能使得所有的区域是连通的,在所有的删边情况中选择字典序最小的一种情况进行输出。
先来思考一下,什么情况下才能使得所有区域是连通的?其实画个图观察不难发现,只有当图中没有环时整个区域才是连通的,现在问题就转化为我们至少删除多少条边才能使得图中没有环,由于树是一个没有环的最大连通子图,所以显然是将图删边使其形成一棵树,这样的话删除的边数一定是最小的,由于题目中要求删除的边的字典序最小,那么我们就可以考虑从编号大的边开始添加边,只要加进去该边不成环就把该边加入图中,这样最后没有加入图中的边就是我们要删除的边,那么我们直接按照字典序进行从小到大输出即可,这个过程就是利用类似kruscal的过程进行实现,只是我们不是按照边权进行排序,而是按照编号进行排序。
下面是代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<vector>
#include<stack>
#include<cmath>
using namespace std;
const int N=2e6+10;
int fu[N],u[N],v[N];
int find(int x)
{
if(x!=fu[x]) fu[x]=find(fu[x]);
return fu[x];
}
stack<int>st;
int main()
{
int T;
cin>>T;
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) fu[i]=i;
for(int i=1;i<=m;i++)
scanf("%d%d",&u[i],&v[i]);
for(int i=m;i>=1;i--)
{
int fx=find(u[i]),fy=find(v[i]);
if(fx==fy)
st.push(i);
else
fu[fx]=fy;
}
printf("%d\n",st.size());
while(!st.empty())
{
printf("%d ",st.top());
st.pop();
}
puts("");
}
return 0;
}