[六省联考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;
}
posted @ 2018-10-11 08:33  skylee03  阅读(438)  评论(0编辑  收藏  举报