2651: 城市改建 樹形DP

我太sb了。。一看輸出方案就瞎jb記錄了一坨信息。。最後發現根本沒有用。。
結果寫了6.7K。。。成功成爲了BZOJ寫的最長跑的最慢的選手2333。。


題目即在一棵樹上刪一邊加一邊,使得新樹的直徑最小。
那麼我們就要維護直徑相關的信息。。於是大力DP。。
首先自底向上DP,設fi 表示以節點i 爲根的子樹的直徑,gi 表示以節點i 爲根的子樹中離i 最遠的點的距離。
假設j,ki 的孩子,且jk
那麼有

gi=max{gj+1}

fi=max{fj,gj+1,gj+gk+2}

然後我們自頂向下DP,類似的,設hi 表示除去以i 爲根的子樹後,剩餘樹的直徑,pi 表示除去以i 爲根的子樹後,離i 最遠點的距離。
j,ki 的兄弟,且jk
那麼有
pi=max{pfai+1,gj+2}

hi=max{hfai,pfai+gj+1,fj,gj+gk+2}

然後就記錄一些前綴max後綴max最大次大什麼的轉移就行了。
至於記錄方案。。只要把f,g 相關的轉移記錄下來就好了,至於p,h 根本用不到。多寫了一坨懶得刪了。

然後我們枚舉刪去某條邊(i,fai) ,那麼有

ans=max{fi,hi,fi+12+hi+12+1}

最後BFS 一下記錄方案。
時間複雜度O(n)

附sb代碼:

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;

const int N=300005;
const int inf=1000000007;
int n,cnt,ans,id;
int head[N],list[N<<1],next[N<<1];
int premx[N],sufmx[N],preid[N],sufid[N],fa[N],f[N],g[N],h[N],p[N],q[N];
pair<int,int> pref[N],preh[N];
int preg[N],prep[N],pre[N],path[N];
bool vis[N];

inline int read()
{
    int a=0,f=1; char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
    return a*f;
}

inline void insert(int x,int y)
{
    next[++cnt]=head[x];
    head[x]=cnt;
    list[cnt]=y;
}

inline int GETANS(int i)
{
    return max(max((f[i]+1)/2+(h[i]+1)/2+1,f[i]),h[i]);
}

inline void clear(int tot)
{
    for (int i=1;i<=tot+1;i++) sufmx[i]=premx[i]=-inf;
}

void DP1(int x)
{
    preg[x]=x,pref[x]=make_pair(x,x);
    for (int i=head[x];i;i=next[i])
        if (list[i]!=fa[x])
        {
            fa[list[i]]=x;
            DP1(list[i]);
        }
    int mx1=-inf,mx2=-inf,j1,j2;
    for (int i=head[x];i;i=next[i])
        if (list[i]!=fa[x])
        {
//          g[x]=max(g[x],g[list[i]]+1);
            if (g[list[i]]+1>g[x]) g[x]=g[list[i]]+1,preg[x]=preg[list[i]];

//          f[x]=max(f[x],f[list[i]]);
            if (f[list[i]]>f[x]) f[x]=f[list[i]],pref[x]=pref[list[i]];

            if (g[list[i]]>mx1) mx2=mx1,mx1=g[list[i]],j2=j1,j1=preg[list[i]];
            else if (g[list[i]]>mx2) mx2=g[list[i]],j2=preg[list[i]];
        }
//  f[x]=max(f[x],g[x]);
    if (g[x]>f[x]) f[x]=g[x],pref[x]=make_pair(preg[x],x);

    if (mx1!=-inf&&mx2!=-inf) 
//      f[x]=max(f[x],mx1+mx2+2);
        if (mx1+mx2+2>f[x])
            f[x]=mx1+mx2+2,pref[x]=make_pair(j1,j2);
}

void DP2(int x)
{
    vector<int> q;
    q.push_back(0);
    for (int i=head[x];i;i=next[i])
        if (list[i]!=fa[x]) q.push_back(list[i]);
//  cout << x << " : ";
//  for (int i=1;i<=tot;i++) cout<< q[i] << " " ;
//  cout << endl;
    int tot=q.size()-1;
    for (int i=1;i<=tot;i++)
    {
//      h[q[i]]=max(h[q[i]],h[x]);
        if (h[x]>h[q[i]]) h[q[i]]=h[x],preh[q[i]]=preh[x];

//      p[q[i]]=max(p[q[i]],p[x]+1);
        if (p[x]+1>p[q[i]]) p[q[i]]=p[x]+1,prep[q[i]]=prep[x];
    }
    clear(tot);
    for (int i=1;i<=tot;i++)
//      premx[i]=max(premx[i-1],f[q[i]]);
        if (f[q[i]]>premx[i-1]) 
            premx[i]=f[q[i]],preid[i]=q[i];
        else premx[i]=premx[i-1],preid[i]=preid[i-1];
    for (int i=tot;i;i--)
//      sufmx[i]=max(sufmx[i+1],f[q[i]]);
        if (f[q[i]]>sufmx[i+1])
            sufmx[i]=f[q[i]],sufid[i]=q[i];
        else sufmx[i]=sufmx[i+1],sufid[i]=sufid[i+1];
    for (int i=2;i<=tot;i++)
//      h[q[i]]=max(h[q[i]],premx[i-1]);
        if (premx[i-1]>h[q[i]]) 
            h[q[i]]=premx[i-1],preh[q[i]]=pref[preid[i-1]];
    for (int i=1;i<tot;i++)
//      h[q[i]]=max(h[q[i]],sufmx[i+1]);
        if (sufmx[i+1]>h[q[i]])
            h[q[i]]=sufmx[i+1],preh[q[i]]=pref[sufid[i+1]];
    clear(tot);
    for (int i=1;i<=tot;i++)
//      premx[i]=max(premx[i-1],g[q[i]]);
        if (g[q[i]]>premx[i-1]) premx[i]=g[q[i]],preid[i]=q[i];
        else premx[i]=premx[i-1],preid[i]=preid[i-1];
    for (int i=tot;i;i--)
//      sufmx[i]=max(sufmx[i+1],g[q[i]]);
        if (g[q[i]]>sufmx[i+1]) sufmx[i]=g[q[i]],sufid[i]=q[i];
        else sufmx[i]=sufmx[i+1],sufid[i]=sufid[i+1];
    for (int i=2;i<=tot;i++)
//      p[q[i]]=max(p[q[i]],premx[i-1]+2);
        if (premx[i-1]+2>p[q[i]]) 
            p[q[i]]=premx[i-1]+2,prep[q[i]]=preg[preid[i-1]];
    for (int i=1;i<tot;i++)
//      p[q[i]]=max(p[q[i]],sufmx[i+1]+2);
        if (sufmx[i+1]+2>p[q[i]])
            p[q[i]]=sufmx[i+1]+2,prep[q[i]]=preg[sufid[i+1]];
    if (tot==1) 
//      h[q[1]]=max(h[q[1]],p[x]);
        if (p[x]>h[q[1]]) 
            h[q[1]]=p[x],preh[q[1]]=make_pair(prep[x],x);
    for (int i=2;i<=tot;i++)
//      h[q[i]]=max(h[q[i]],p[x]+premx[i-1]+1);
        if (p[x]+premx[i-1]+1>h[q[i]])
            h[q[i]]=p[x]+premx[i-1]+1,preh[q[i]]=make_pair(preg[preid[i-1]],prep[x]);
    for (int i=1;i<tot;i++) 
//      h[q[i]]=max(h[q[i]],p[x]+sufmx[i+1]+1);
        if (p[x]+sufmx[i+1]+1>h[q[i]])
            h[q[i]]=p[x]+sufmx[i+1]+1,preh[q[i]]=make_pair(preg[sufid[i+1]],prep[x]);
    for (int i=2;i<tot;i++)
//      h[q[i]]=max(h[q[i]],premx[i-1]+sufmx[i+1]+2);
        if (premx[i-1]+sufmx[i+1]+2>h[q[i]])
            h[q[i]]=premx[i-1]+sufmx[i+1]+2,preh[q[i]]=make_pair(preg[preid[i-1]],preg[sufid[i+1]]);
    int mx1,mx2,j1,j2;
    mx1=-inf; mx2=-inf;
    for (int i=1;i<=tot;i++)
    {
        if (mx1!=-inf&&mx2!=-inf) 
            //h[q[i]]=max(h[q[i]],mx1+mx2+2);
            if (mx1+mx2+2>h[q[i]])
                h[q[i]]=mx1+mx2+2,preh[q[i]]=make_pair(j1,j2);
        if (g[q[i]]>mx1) mx2=mx1,mx1=g[q[i]],j2=j1,j1=preg[q[i]];
        else if (g[q[i]]>mx2) mx2=g[q[i]],j2=preg[q[i]];
    }
    mx1=-inf; mx2=-inf;
    for (int i=tot;i;i--)
    {
        if (mx1!=-inf&&mx2!=-inf) 
            //h[q[i]]=max(h[q[i]],mx1+mx2+2);
            if (mx1+mx2+2>h[q[i]])
                h[q[i]]=mx1+mx2+2,preh[q[i]]=make_pair(j1,j2);
        if (g[q[i]]>mx1) mx2=mx1,mx1=g[q[i]],j2=j1,j1=preg[q[i]];
        else if (g[q[i]]>mx2) mx2=g[q[i]],j2=preg[q[i]];
    }
    for (int i=1;i<=tot;i++) DP2(q[i]);
}

inline void BFS(int x)
{
    memset(vis,0,sizeof(vis));
    memset(path,0,sizeof(path));
    queue<int> q;
    q.push(x); vis[x]=true;
    while (!q.empty())
    {
        int x=q.front(); q.pop();
//      cout << x << " ";
        for (int i=head[x];i;i=next[i])
            if (!vis[list[i]])
            {
                vis[list[i]]=1;
                path[list[i]]=x;
                q.push(list[i]);
            }
    }
}

inline int find(int x,int ff)
{
//  cout << "now : " ;
    fa[x]=ff; DP1(x);
    int st=pref[x].first,en=pref[x].second;
//  cout << st <<  " " << en <<endl;
    BFS(st);
//  for (int i=1;i<=n;i++) cout << path[i] << " ";
//  puts("");
    int cnt=0;
    int i;
    for (i=en;i;i=path[i])
    {
//      cout << i << " ";
        if (++cnt==f[x]/2+1) break;
    }
//  cout << endl;
    return i;
}

int main()
{
//  freopen("A1316.out","w",stdout);

    n=read();
    for (int i=1;i<n;i++)
    {
        int u=read(),v=read();
        insert(u,v); insert(v,u);
    }
    DP1(1); DP2(1);

//  for (int i=1;i<=n;i++) cout << p[i] <<" ";
//  cout << endl;

    ans=inf;
    for (int i=1;i<=n;i++)
//      ans=min(ans,max(max((f[i]+1)/2+(h[i]+1)/2+1,f[i]),h[i]));
        if (GETANS(i)<ans) ans=GETANS(i),id=i;
    int A=id,B=fa[id];
    memset(fa,0,sizeof(fa));
    memset(f,0,sizeof(f));
    memset(g,0,sizeof(g));
    printf("%d\n%d %d\n%d %d\n",ans,A,B,find(A,B),find(B,A));
//  for (int i=1;i<=n;i++)
//      cout << i << " " << fa[i] << endl;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章