bzoj4871: [Shoi2017]摧毁“树状图” //树形dp

bzoj4871: [Shoi2017]摧毁“树状图”


题意

给出一棵大小为N(<=5e5)的树,求树上两条边不相交路径能把这棵树分成的联通块个数的最大值。


背景

在年底之前改完了一道今年省选题xd
庆幸这道题出在了我只会暴力的时候…
以及,像上次那个寿司餐厅一样,我凭着大半年前的记忆去做这道题,于是又审错了题,写了一个边可以相交的东西…(好在变成边不相交只需要稍微删几个状转


题解

这个好像并不能用语言很好地描述…
放个图好了ww

bzoj4871: [Shoi2017]摧毁“树状图” //树形dp_第1张图片

代码

其实写起来比想象中要短一些呢

//这个是压行压得不太狠的版本…在bz上是交了一个压到1400+b的
#include
#define N 500005
#define mn(x,y) if(x
using namespace std;
int T,op,n,j,d[N][4],deg[N],ans,
    to[N<<1],hd[N<<1],lk[N],cnt;
bool vis[N];
void dfs(int k)
{
    d[k][0]=d[k][2]=d[k][3]=deg[k];
    d[k][1]=vis[k]=1;
    int m=0;
    for(int x,i=lk[k];i;i=hd[i])
    if(!vis[x=to[i]])
    {
        dfs(x);
        mn(ans,d[k][3]+d[x][0]-(k==1));
        mn(ans,d[k][0]+d[x][3]-(k==1));
        mn(ans,d[k][1]+d[x][2]);
        mn(ans,d[k][1]+d[x][1]-1);
        mn(ans,d[k][2]+d[x][1]-(k==1));
        mn(ans,d[k][2]+d[x][2]-(k==1));
        mn(d[k][1],d[x][1]);
        mn(d[k][1],d[x][2]+1);
        mn(d[k][3],d[k][0]+d[x][2]-1);
        mn(d[k][3],d[k][2]+d[x][0]-1);
        mn(d[k][3],d[x][3]+deg[k]-1);
        mn(d[k][3],d[x][0]+m+deg[k]-2);
        mn(d[k][3],d[k][0]+d[x][1]-1);
        mn(d[k][2],d[k][0]+d[x][0]-1);
        mn(d[k][0],d[x][0]+deg[k]-1);
        mn(d[k][2],d[k][0]);
        mn(d[k][3],d[k][2]);
        mn(m,d[x][1]);mn(m,d[x][2]);
    }
    deg[k]=lk[k]=vis[k]=0;
}
inline void add(int u,int v)
{to[++cnt]=v,hd[cnt]=lk[u],lk[u]=cnt,deg[u]++;}
int u,v;
char ch;
inline void rd(int &x)
{
    x=0;
    do ch=getchar();
    while(ch<'0'||ch>'9');
    do x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    while(ch>='0'&&ch<='9');
}
int main()
{
    rd(T),rd(op);
    while(T--)
    {
        rd(n);
        for(int i=0;ifor(int i=2;i<=n;i++)
        rd(u),rd(v),add(u,v),add(v,u),deg[i]--;
        dfs(1),printf("%d\n",ans);
        cnt=ans=0;
    }
}

你可能感兴趣的:(树形dp)