CF708C 【Centroids】树上DP

洛谷同步博客

1.我们先来简化一下问题

如果题目不让我们改造这棵树,就很好求了。
先求出size[e]size[e](如下图),ee为无根树中的任意一条有向边(我们在邻接表中使用一对有向边eee\overline{e}来表示,其中e\overline{e}ee的反向边,表示以tail[e]tail[e](表示边e的尾)为根的子树的大小。可知size[e]=nsize[e]size[\overline{e}]=n-size[e]
CF708C 【Centroids】树上DP
要求出size[e]size[e]size[e]size[\overline{e}],可以用一个dfsdfs来解决(e\overline{e}可以用一个小技巧:e^1

上代码:

void dfs(int u,int e)
{
    size[e]=1;
    for(int i=0;i<(int)G[u].size();i++)
        if(G[u][i]!=(e^1))
        {
            int v=edges[G[u][i]].v;
            dfs1(v,G[u][i]);
            add(u,G[u][i]);
            size[e]+=size[G[u][i]];
        }
    size[e^1]=n-size[e];
}

这样,就可以了:把每个节点的各个子节点的sizesize值扫描一遍,有size[v]n2(vson[u])size[v]≥\frac{n}{2}(v\in son[u])就说明uu不是树的中心。

2.说了半天,回到原问题(还有啊!qwqqwq!)

做好迎接挑战的准备吧!

我们要把一条边删去,并连上另一条新边,也就是说,要把一个子树切割下来,在把他连到新的节点上。
我们可以计算一个c[e]c[e]ee的定义同size[e]size[e]),表示以tail[e]tail[e]为根的子树中最多可以割下多少个节点,可知c[e]n2c[e] \le \frac{n}{2}
可以在原来的dfsdfs的基础上再加一个dfsdfs(并用一个数据结构来辅助实现):

void add(int u,int i)
{
    if(best[u]<=c[i])
    {
        sec[u]=best[u];
        best[u]=c[i];
        idx[u]=i;
    }
    else sec[u]=max(sec[u],c[i]);
}
int query(int u,int i)
{
    if(i!=idx[u]) return best[u];
    else return sec[u];
}
void dfs1(int u,int e)
{
    size[e]=1;
    c[e]=0;
    for(int i=0;i<(int)G[u].size();i++)
        if(G[u][i]!=(e^1))
        {
            int v=edges[G[u][i]].v;
            dfs1(v,G[u][i]);
            add(u,G[u][i]);
            size[e]+=size[G[u][i]];
            c[e]=max(c[e],c[G[u][i]]);
        }
    size[e^1]=n-size[e];
    if(size[e]<=n/2) c[e]=size[e];
}
void dfs2(int u,int e)
{
    add(u,e^1);
    for(int i=0;i<(int)G[u].size();i++)
        if(G[u][i]!=(e^1))
        {
            if(size[G[u][i]^1]<=n/2) c[G[u][i]^1]=size[G[u][i]^1];
            else c[G[u][i]^1]=query(u,G[u][i]);
            dfs2(edges[G[u][i]].v,G[u][i]);
        }
}

3.于是我们就大功告成了

献上我丑陋的代码:

#include<iostream>
#include<vector> 
using namespace std;
const int maxn=800005;
struct Edge
{
    int u,v;
    Edge(int x,int y): u(x),v(y){}
};
int n,size[maxn],c[maxn],best[maxn],sec[maxn],idx[maxn];
vector<Edge> edges;
vector<int> G[maxn];
void add(int u,int i)
{
    if(best[u]<=c[i])
    {
        sec[u]=best[u];
        best[u]=c[i];
        idx[u]=i;
    }
    else sec[u]=max(sec[u],c[i]);
}
int query(int u,int i)
{
    if(i!=idx[u]) return best[u];
    else return sec[u];
}
void dfs1(int u,int e)
{
    size[e]=1;
    c[e]=0;
    for(int i=0;i<(int)G[u].size();i++)
        if(G[u][i]!=(e^1))
        {
            int v=edges[G[u][i]].v;
            dfs1(v,G[u][i]);
            add(u,G[u][i]);
            size[e]+=size[G[u][i]];
            c[e]=max(c[e],c[G[u][i]]);
        }
    size[e^1]=n-size[e];
    if(size[e]<=n/2) c[e]=size[e];
}
void dfs2(int u,int e)
{
    add(u,e^1);
    for(int i=0;i<(int)G[u].size();i++)
        if(G[u][i]!=(e^1))
        {
            if(size[G[u][i]^1]<=n/2) c[G[u][i]^1]=size[G[u][i]^1];
            else c[G[u][i]^1]=query(u,G[u][i]);
            dfs2(edges[G[u][i]].v,G[u][i]);
        }
}
int main()
{
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int u,v;
        cin>>u>>v;
        edges.push_back(Edge(u,v));
        edges.push_back(Edge(v,u));
        G[u].push_back(edges.size()-2);
        G[v].push_back(edges.size()-1);
    }
    dfs1(1,edges.size());
    dfs2(1,edges.size());
    for(int i=1;i<=n;i++)
    {
        bool ok=true;
        for(int j=0;j<(int)G[i].size();j++)
            if(size[G[i][j]]-c[G[i][j]]>n/2)
            {
                ok=false;
                break;
            }
        cout<<ok<<' ';
    }
    return 0;
}

P.S.:P.S.:如有不当,请指出。