【BZOJ4871】【SHOI2017】摧毀“樹狀圖”
阿新 • • 發佈:2019-02-16
題目大意
在一棵樹上選擇兩條邊不相交的鏈(可以是單點),問剩餘聯通塊數量最大為多少。
Solution
當你發現這題可以用DP做時,就只剩下調程式了。
考慮子樹的每個狀態分類討論合併一下即可。感覺思路清晰還是不容易出錯的。
PS:話說為什麼看到“樹狀圖”和“treediagram”第一個想到的是《魔法禁書目錄》>w<
/**************************************************************
Problem: 4871
User: llgyc
Language: C++
Result: Accepted
Time:1628 ms
Memory:5588 kb
****************************************************************/
#include<set>
#include<map>
#include<queue>
#include<cmath>
#include<string>
#include<cstdio>
#include<vector>
#include<cassert>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rep(i,a,b) for (int i=a; i<=b; i++)
#define per(i,a,b) for (int i=a; i>=b; i--)
#define debug(x) {cout<<(#x)<<" "<<x<<endl;}
using namespace std;
typedef long long LL;
inline int read() {
int x=0,f=1; char ch=getchar();
while (!(ch>='0'&&ch<='9')) {if (ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9' ) {x=x*10+(ch-'0'); ch=getchar();}
return x*f;
}
const int N = 100005;
struct edge{int go,next;}e[N<<1]; int cnt=0,last[N]; inline void ins(int u,int v) {e[++cnt].go=v; e[cnt].next=last[u]; last[u]=cnt;}
int n;
int dp[N][6];
inline void dfs(int x,int fa) {
int mx1=-N,mx2=-N,mx3=-N,mx4=-N,mx=-N,pos1=0,pos2=0,tot=0;
for (register int i=last[x];i;i=e[i].next) {
if (e[i].go==fa) continue;
int y=e[i].go; dfs(y,x); ++tot;
//one
dp[x][1]=max(dp[x][1],max(dp[y][0]+1,max(dp[y][1],dp[y][2]+1)));
dp[x][2]=max(dp[x][2],dp[y][2]);
if (dp[y][2]>=mx1) mx4=mx3,mx3=mx2,mx2=mx1,pos2=pos1,mx1=dp[y][2],pos1=y;
else if (dp[y][2]>=mx2) mx4=mx3,mx3=mx2,mx2=dp[y][2],pos2=y;
else if (dp[y][2]>=mx3) mx4=mx3,mx3=dp[y][2];
else if (dp[y][2]>=mx4) mx4=dp[y][2];
mx=max(dp[y][0],max(dp[y][1],dp[y][2]));
//two
dp[x][4]=max(dp[x][4],max(dp[y][3]+1,max(dp[y][4],dp[y][5]+1)));
dp[x][5]=max(dp[x][5],dp[y][5]);
}
if (!tot) {dp[x][0]=0; dp[x][1]=-N; dp[x][2]=dp[x][3]=0; dp[x][4]=-N; dp[x][5]=0; return;}
if (tot>=2) dp[x][0]=max(dp[x][0],mx1+mx2+tot-2),dp[x][2]+=tot-1,dp[x][5]+=tot-1,dp[x][5]=max(dp[x][5],mx1+mx2+tot-2);
dp[x][0]=max(dp[x][0],tot); dp[x][2]=max(dp[x][2],tot);
dp[x][3]=max(dp[x][3],tot); dp[x][5]=max(dp[x][5],tot);
dp[x][3]=max(dp[x][3],mx+tot-1); dp[x][5]=max(dp[x][5],mx1+mx2+mx3+tot-3);
dp[x][3]=max(dp[x][3],mx1+mx2+mx3+tot-3);
dp[x][3]=max(dp[x][3],mx1+mx2+mx3+mx4+tot-4);
int mx00=0,mx01=0,mx02=0,mx05=0;
for (register int i=last[x];i;i=e[i].next) {
if (e[i].go==fa) continue;
int y=e[i].go;
//one
dp[x][0]=max(dp[x][0],dp[y][2]+tot-1);
//two
dp[x][3]=max(dp[x][3],dp[y][5]+tot-1);
dp[x][3]=max(dp[x][3],max(dp[y][2]+max(mx00,max(mx01,mx02)),max(dp[y][0],max(dp[y][1],dp[y][2]))+mx02)+tot-2);
dp[x][3]=max(dp[x][3],max(dp[y][2]+mx05,mx02+dp[y][5])+tot-2);
if (y==pos1) dp[x][3]=max(dp[x][3],mx2+mx3+max(dp[y][0],dp[y][1])+tot-3);
else if (y==pos2) dp[x][3]=max(dp[x][3],mx1+mx3+max(dp[y][0],dp[y][1])+tot-3);
else dp[x][3]=max(dp[x][3],mx1+mx2+max(dp[y][0],dp[y][1])+tot-3);
dp[x][4]=max(dp[x][4],max(max(dp[y][0],dp[y][2])+mx01,dp[y][1]+max(mx00,mx02)));
dp[x][4]=max(dp[x][4],max(max(dp[y][0],dp[y][2])+max(mx00,mx02)+1,dp[y][1]+mx01-1));
dp[x][5]=max(dp[x][5],max(dp[y][0],max(dp[y][1],dp[y][2]))+tot-1);
dp[x][5]=max(dp[x][5],max(dp[y][2]+max(mx00,max(mx01,mx02)),max(dp[y][0],max(dp[y][1],dp[y][2]))+mx02)+tot-2);
mx00=max(mx00,dp[y][0]);
mx01=max(mx01,dp[y][1]);
mx02=max(mx02,dp[y][2]);
mx05=max(mx05,dp[y][5]);
}
}
int main() {
#ifndef ONLINE_JUDGE
// freopen("treediagram.in","r",stdin);
// freopen("treediagram.out","w",stdout);
#endif
int T=read(),x=read();
while (T--) {
int p0,p1,h0,h1; n=read();
if (x==1) p0=read(),p1=read();
if (x==2) p0=read(),p1=read(),h0=read(),h1=read();
rep(i,1,n-1) {int u=read(),v=read(); ins(u,v); ins(v,u);}
dfs(1,0);
int ans=0; rep(i,3,5) ans=max(ans,dp[1][i]);
printf("%d\n",ans);
cnt=0; rep(i,1,n) last[i]=0;
rep(i,1,n) rep(j,0,5) dp[i][j]=0;
}
return 0;
}