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;
    }
    
  • 相关阅读:
    外部类和内部类的创建调用实例2个
    构造函数实例化
    前端学习(二十三)DOM操作,事件(笔记)
    前端学习(二十二)css3(笔记)
    前端学习(二十一)初识h5(笔记)
    前端学习(二十)jquery属性(笔记)
    前端学习(十九)jquery(笔记)
    前端学习(十八)js的json(笔记)
    前端学习(十七)js数组(笔记)
    前端学习(十六)字符串(笔记)
  • 原文地址:https://www.cnblogs.com/owenyu/p/7142527.html
Copyright © 2011-2022 走看看