洛谷 P3748 [六省联考 2017] 摧毁“树状图”

题目链接

看来这次出题人拉了坨大的,他还真有勇气,我一看,可以分成两种情况讨论:

  1. 两条链相交。因为题目要求交点最多一个,所以可以枚举交点,下面挂 \(0 \sim 4\) 条最大的链计算答案。

  2. 两条链无交。这时候可以把树分割成两棵子树,枚举割断的边计算答案。不妨可以钦定下面子树的根节点被链经过。

然后就可以换根 dp 了,状态设计和转移可以参考下面代码。

但是,出题人给了我们 \(x = 0/1/2\) 三种情况。不过,由于题目保证给出的路线最优,全部都当成 \(x = 0\) 来做就行啦。

时间复杂度 \(\text O (n)\)

/*
“答案”表示连通块数最大值 

f[x][0~3]:x 下面挂的链的第 1~4 大答案 
g[x]:链端点是 x 的答案
h[x]:链在 x 子树内,经过 x 的答案 
p[x]:链在 x 子树内,不经过 x 的答案
*/

#include<cstdio>
#include<algorithm>
#define N 500005
using namespace std;

int T,cxk;
int read() {
	int x=0; char c=getchar();
	for(;c<'0'||c>'9';c=getchar());
	for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
	return x;
}
void write(int x) {
	if(x>9) write(x/10);
	putchar('0'+x%10);
}
int n,ans,deg[N],g[N],h[N];
int tot,head[N],nxt[N*2],ver[N*2];
void insert(int x,int y) {
	ver[++tot]=y,nxt[tot]=head[x],head[x]=tot;
}
struct kmax {
	int k,mx[4],id[4];
	int& operator[](int x) {return mx[x];}
	void init(int u) {
		k=u;
		for(int i=0;i<k;i++) mx[i]=id[i]=0;
	}
	void ins(int x,int c) {
		if(c>mx[k-1]) {
			mx[k-1]=c,id[k-1]=x;
			for(int j=k-1;j&&mx[j]>mx[j-1];j--)
				swap(mx[j],mx[j-1]),swap(id[j],id[j-1]);
		}
	}
	void del(int x) {
		for(int i=0;i<k-1;i++)
			if(id[i]==x)
				swap(mx[i],mx[i+1]),swap(id[i],id[i+1]);
		if(id[3]==x)
			mx[3]=id[3]=0;
	}
} f[N],p[N];
void upd(int x) {
	g[x]=max(deg[x],f[x][0]+deg[x]-1);
	h[x]=max(g[x],f[x][0]+f[x][1]+deg[x]-2);
}
void dp(int x,int fa) {
	deg[x]=0,f[x].init(4),p[x].init(2);
	for(int i=head[x],y;i;i=nxt[i]) {
		if((y=ver[i])==fa) continue;
		dp(y,x),deg[x]++,f[x].ins(y,g[y]),p[x].ins(y,max(h[y]+1,p[y][0]));
	}
	upd(x);
}
void dfs(int x,int fa) {
	int sum=deg[x]; ans=max(ans,sum);
	for(int i=0;i<4;i++) sum+=f[x][i]-1,ans=max(ans,sum);
	int deg_=deg[x]; kmax f_=f[x],p_=p[x];
	for(int i=head[x],y;i;i=nxt[i]) {
		if((y=ver[i])==fa) continue;
		deg[x]--,f[x].del(y),p[x].del(y),upd(x);
		ans=max(ans,h[y]+max(h[x],p[x][0]));
		deg[y]++,f[y].ins(x,g[x]),p[y].ins(y,max(h[x]+1,p[x][0]));
		dfs(y,x),deg[x]=deg_,f[x]=f_,p[x]=p_;
	}
}
int main() {
	scanf("%d%d",&T,&cxk);
	XJX:while(T--) {
		tot=0;
		for(int i=1;i<=n;i++) head[i]=0;
		n=read();
		for(int _=1;_<=cxk;_++) read(),read();
		for(int i=1,x,y;i<n;i++) {
			x=read(),y=read();
			insert(x,y),insert(y,x);
		}
		ans=0,dp(1,0),dfs(1,0);
		write(ans),putchar('\n');
	}
	return 0;
}
posted @ 2026-01-19 19:30  yemuzhe  阅读(1)  评论(0)    收藏  举报