[六省联考2017]摧毁“树状图”
[六省联考2017]摧毁“树状图”
题目大意:
给你一个\(n(n\le5\times10^5)\)个点的图,从图中选两条链,删掉链上所有点以及所有相连的边,使得剩下的连通块数目最多,求连通块个数。
思路:
树形DP。
f[x][0]
:穿过\(x\)向上的半条链f[x][1]
:不穿过\(x\)且完全在子树内的一条链f[x][2]
:穿过\(x\)且完全在子树内的一条链f[x][3]
:穿过\(x\)向上的半条连以及完全在子树内的一条链
然后就是各种大力讨论。
这个有图示的题解比较好懂。
源代码:
#include<cstdio>
#include<cctype>
#include<vector>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=5e5+1;
std::vector<int> e[N];
inline void add_edge(const int &u,const int &v) {
e[u].push_back(v);
e[v].push_back(u);
}
int f[N][4],ans;
inline void upd(int &a,const int &b) {
a=std::max(a,b);
}
void dfs(const int &x,const int &par) {
const bool isrt=x==1;
const int deg=e[x].size()-!isrt;
f[x][0]=f[x][2]=f[x][3]=deg;
f[x][1]=1;
int max=0;
for(unsigned i=0;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==par) continue;
dfs(y,x);
upd(ans,f[x][0]+f[y][3]-isrt);
upd(ans,f[x][3]+f[y][0]-isrt);
upd(ans,f[x][1]+f[y][1]-1);
upd(ans,f[x][1]+f[y][2]);
upd(ans,f[x][2]+f[y][1]-isrt);
upd(ans,f[x][2]+f[y][2]-isrt);
upd(f[x][1],f[y][1]);
upd(f[x][1],f[y][2]+1);
upd(f[x][3],f[y][3]+deg-1);
upd(f[x][3],f[y][0]+max+deg-2);
upd(f[x][3],f[x][0]+f[y][1]-1);
upd(f[x][3],f[x][0]+f[y][2]-1);
upd(f[x][3],f[x][2]+f[y][0]-1);
upd(f[x][2],f[x][0]+f[y][0]-1);
upd(f[x][0],f[y][0]+deg-1);
upd(f[x][2],f[x][0]);
upd(f[x][3],f[x][2]);
upd(max,f[y][1]);
upd(max,f[y][2]);
}
}
int main() {
const int T=getint(),x=getint();
for(register int i=0;i<T;i++) {
const int n=getint();
for(register int i=0;i<x*2;i++) getint();
for(register int i=1;i<n;i++) {
add_edge(getint(),getint());
}
ans=0;
dfs(1,0);
printf("%d\n",ans);
for(register int i=1;i<=n;i++) {
e[i].clear();
}
}
return 0;
}