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


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

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    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
    ";
    #else
        const char LL[]="%lld
    ";
    #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<n;i++)
            {
                int x=read(),y=read();
                addedge(x,y),addedge(y,x);
            }
            dfs(1,1);
            printf("%d
    ",max(max(f[1][0],f[1][1],f[1][2]),max(f[1][3],f[1][4],f[1][5])));
        }
        return 0;
    }
  • 相关阅读:
    PHP MySQL 插入多条数据
    PHP MySQL 插入数据
    PHP MySQL 创建数据表
    PHP MySQL 创建数据库
    PHP 连接 MySQL
    PHP MySQL 简介
    PHP JSON
    12_短信发送器_发送短信实现
    11_短信发送器_快速回复页面实现
    10_短信发送器_获取电话号码
  • 原文地址:https://www.cnblogs.com/Gloid/p/10016099.html
Copyright © 2020-2023  润新知