zoukankan      html  css  js  c++  java
  • CF708C-Centroids

    题目

    一棵树的重心定义为一个点满足删除这个点后最大的连通块大小小于等于原来这颗树大小的一半。

    给出一棵树,一次操作为删除一条边再添加一条边,操作结束后必须仍为一棵树。问这颗树的每个点是否可以通过一次操作使它变成新树的重心。

    (nle 4 imes 10^5)

    分析

    如果一个点原来不是重心,那么这个点必定只有一个子树的大小大于(frac{n}{2}) 。要让这个点变成重心,那么需要在这个子树中切出尽量大的一块,使它的大小小于等于(frac{n}{2}) 。如果这颗子树中剩下的大小也小于等于(frac{n}{2}) ,那么就可以,否则一定不行。

    于是问题就变成了求对于每个点,以它为根的子树中最大能切出一个多大的子树,大小小于等于 (frac{n}{2}) ;除去这个点的子树剩下的树中最大能切出多大的子树,大小小于等于(frac{n}{2}) (即上面的那颗“子树”)。

    这可以通过两次dfs(树形dp)得到,一次求( ext{down[x]}),一次用( ext{down})的信息求出( ext{up[x]}) 。一个点的( ext{up})有可能是父亲的( ext{up}) ,也有可能是切掉它连去父亲的那条边得到的子树大小,也可能是父亲的另一颗子树的( ext{down})

    这题的关键其实在于想到**在这个子树中切出尽量大的一块,使它的大小小于等于(frac{n}{2}) ** ,而不是找其中重心之类思路。

    代码

    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<algorithm>
    using namespace std;
    int read() {
        int x=0,f=1;
        char c=getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
        for (;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    const int maxn=4e5+1;
    int n,hf,size[maxn],up[maxn],down[maxn],which[maxn],msize[maxn];
    bool ans[maxn];
    vector<int> g[maxn];
    void add(int x,int y) {g[x].push_back(y);}
    int Size(int x,int fa) {
        int &sz=size[x]=1,&ms=msize[x]=0;
        for (int v:g[x]) if (v!=fa) {
            int ret=Size(v,x);
            sz+=ret,ms=max(ms,ret);
        }
        ms=max(ms,n-size[x]);
        return sz;
    }
    void Root(int x,int fa) {
        for (int v:g[x]) if (v!=fa && size[v]>=hf) which[x]=v,Root(v,x);
    }
    void Down(int x,int fa) {
        for (int v:g[x]) if (v!=fa) Down(v,x),down[x]=max(down[x],down[v]);
        if (size[x]<=hf) down[x]=size[x];
    }
    void Up(int x,int fa) {
        pair<int,int> fir(0,0),sec(0,0);
        for (int v:g[x]) if (v!=fa) if (down[v]>fir.first) swap(fir,sec),fir=make_pair(down[v],v); else if (down[v]>sec.first) sec=make_pair(down[v],v);
        for (int v:g[x]) if (v!=fa) {
            int &nxt=up[v]=max(up[x],v==fir.second?sec.first:fir.first);
            if (n-size[v]<=hf) nxt=max(nxt,n-size[v]);
            Up(v,x);
        }
    }
    void dfs(int x,int fa) {
        if (msize[x]<=hf) ans[x]=true; else {
            if (which[x]>0) ans[x]=(size[which[x]]-down[which[x]]<=hf); else
            ans[x]=(n-size[x]-up[x]<=hf);
        }
        for (int v:g[x]) if (v!=fa) dfs(v,x);
    }
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("test.in","r",stdin);
    #endif
        hf=(n=read())>>1;
        for (int i=1;i<n;++i) {
            int x=read(),y=read();
            add(x,y),add(y,x);
        }
        Size(1,1),Root(1,1);
        Down(1,1);
        Up(1,1);
        dfs(1,0);
        for (int i=1;i<=n;++i) putchar("01"[ans[i]]),putchar(" 
    "[i==n]);
        return 0;
    }
    
  • 相关阅读:
    Redis学习六(java中使用redis)
    Redis学习五(新数据类型)
    Redis学习四(发布和订阅)
    Redis学习三(配置文件说明)
    Redis学习二(常用五大数据类型)
    Redis学习一(源码安装redis)
    RocketMq常见问题记录
    总结多种容器化技术对比
    关于Redis集群部署和持久化的相关问题
    配置Jenkins连接kubernetes的Pod Template模板
  • 原文地址:https://www.cnblogs.com/owenyu/p/7142527.html
Copyright © 2011-2022 走看看