洛谷 P3748 [六省联考 2017] 摧毁“树状图”
看来这次出题人拉了坨大的,他还真有勇气,我一看,可以分成两种情况讨论:
-
两条链相交。因为题目要求交点最多一个,所以可以枚举交点,下面挂 \(0 \sim 4\) 条最大的链计算答案。
-
两条链无交。这时候可以把树分割成两棵子树,枚举割断的边计算答案。不妨可以钦定下面子树的根节点被链经过。
然后就可以换根 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;
}

浙公网安备 33010602011771号