1. 程式人生 > >【BZOJ4871】【SHOI2017】摧毀“樹狀圖”

【BZOJ4871】【SHOI2017】摧毀“樹狀圖”

題目大意

  在一棵樹上選擇兩條邊不相交的鏈(可以是單點),問剩餘聯通塊數量最大為多少。
  T105n5×105

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; }