BZOJ4871 Shoi2017摧毁“树状图”(树形dp)

  设f[i][0/1/2/3/4/5]表示i子树中选一条链不包含根/i子树中选一条链包含根但不能继续向上延伸/i子树中选一条链可以继续向上延伸/选两条链不包含根/选两条链包含根但不能继续向上延伸/选两条链能继续向上延伸,大力讨论即可。代码看起来很(mo)有(ming)意(qi)思(miao)。

#include 
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
#define N 500010
char getc(){
     char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){
     return m==0?n:gcd(m,n%m);}
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {
     if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
int T,n,p[N],f[N][6],t;
int mx[4][6];
struct data{
     int to,nxt;
}edge[N<<1];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
inline void up(int &x,int y){x=max(x,y);}
inline int max(int x,int y,int z){
     return max(max(x,y),z);}
void update(int x)
{
    for (int i=0;i<6;i++)
        for (int j=0;j<4;j++)
        if (f[x][i]>f[mx[j][i]][i])
        {
            for (int k=3;k>j;k--) mx[k][i]=mx[k-1][i];
            mx[j][i]=x;break;
        }
}
int findmx(int x){
     return f[mx[0][x]][x];}
int findmx(int x,int y)
{
    if (mx[0][x]!=mx[0][y]) return f[mx[0][x]][x]+f[mx[0][y]][y];
    return max(f[mx[0][x]][x]+f[mx[1][y]][y],f[mx[1][x]][x]+f[mx[0][y]][y]);
}
int findmx(int x,int y,int z)
{
    int s=-n;
    for (int i=0;i<4;i++)
        for (int j=i+1;j<4;j++)
            for (int k=0;k<4;k++)
            if (mx[k][z]!=mx[i][x]&&mx[k][z]!=mx[j][y]) up(s,f[mx[k][z]][z]+f[mx[i][x]][x]+f[mx[j][y]][y]);
    return s;
}
int findmx(int a,int b,int c,int d){
     return f[mx[0][a]][a]+f[mx[1][b]][b]+f[mx[2][c]][c]+f[mx[3][d]][d];}
void dfs(int k,int from)
{
    int son=0;
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=from) son++,dfs(edge[i].to,k);
    memset(mx,0,sizeof(mx));
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=from) update(edge[i].to);
    f[k][0]=max(findmx(0),findmx(1)+1,findmx(2)+1);
    f[k][1]=findmx(2,2)+son-2;
    f[k][2]=max(son,findmx(2)+son-1);
    f[k][3]=max(findmx(3),findmx(4)+1,findmx(5)+1);
    for (int i=0;i<3;i++)
        for (int j=i;j<3;j++)
        up(f[k][3],findmx(i,j)+1-(i==0)-(j==0));
    f[k][4]=max(findmx(2,2,2,2)-4,max(findmx(2,2,0)-3,findmx(2,2,1)-3),findmx(2,5)-2)+son;
    f[k][5]=max(max(findmx(5)-1,findmx(2,2,2)-3,max(findmx(2,2),findmx(2,1),findmx(2,0))-2),max(findmx(0),findmx(1),findmx(2))-1)+son;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4871.in","r",stdin);
    freopen("bzoj4871.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    T=read();int op=read();
    while (T--)
    {
        n=read();if (op>=1) read(),read();if (op==2) read(),read();
        t=0;for (int i=1;i<=n;i++) p[i]=0;
        f[0][0]=f[0][1]=f[0][2]=f[0][3]=f[0][4]=f[0][5]=-n;
        for (int i=1;i)
        {
            int x=read(),y=read();
            addedge(x,y),addedge(y,x);
        }
        dfs(1,1);
        printf("%d\n",max(max(f[1][0],f[1][1],f[1][2]),max(f[1][3],f[1][4],f[1][5])));
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/Gloid/p/10016099.html

你可能感兴趣的:(BZOJ4871 Shoi2017摧毁“树状图”(树形dp))