【BZOJ4871】【SHOI2017】摧毁“树状图”

题目大意

  在一棵树上选择两条边不相交的链(可以是单点),问剩余联通块数量最大为多少。
   T105n5×105


Solution

  当你发现这题可以用DP做时,就只剩下调程序了。
  考虑子树的每个状态分类讨论合并一下即可。感觉思路清晰还是不容易出错的。
  
  PS:话说为什么看到“树状图”和“treediagram”第一个想到的是《魔法禁书目录》>w<
  

/**************************************************************
    Problem: 4871
    User: llgyc
    Language: C++
    Result: Accepted
    Time:1628 ms
    Memory:5588 kb
****************************************************************/

#include
#include
#include
#include
#include<string>
#include
#include<vector>
#include
#include
#include
#include
#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)<<" "<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;
}

你可能感兴趣的:(BZOJ,OI,动态规划)