2019icpc徐州站 M 【Kill the tree】(找各点重心)
题目链接:https://nanti.jisuanke.com/t/42552
题意:一开始建1个以1为root的树,然后找以各个节点作为根其子树中的重心是谁
解法:推荐博客:https://www.cnblogs.com/ctyakwf/p/12010370.html
这个题是一个非常不错的重心性质问题。我们以son代表以x为根的重儿子。倘若siz[son]*2>=siz[x],那么这个重心势必在son的重心和x之间,否则就是x。所以呢我们需要在res[son]至x中间爬,爬到所谓真正的x的重心(我们一开始都初始化x的重心为他自己),一旦siz[x]-2*siz[res[son]]>0,那么代表这个x的真正重心还能往上爬。爬到<=为止。最后你需要特判一下if(siz[x]==2*siz[res[x]])。这种等于情况显然就是会出现2个重心的情况,会出现两个解。
AC代码:
#include<bits/stdc++.h> #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl '\n' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; const int maxn=2e5+5; int tot,head[maxn]; struct E{ int to,next; }edge[maxn<<1]; void add(int u,int v){ edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } int fa[maxn],n;int siz[maxn],res[maxn],res1[maxn]; void dfs(int x,int f){ siz[x]=1;res[x]=x; int son=0; for(int i=head[x];i!=-1;i=edge[i].next){ int v=edge[i].to; if(v==f) continue; fa[v]=x; dfs(v,x); siz[x]+=siz[v]; if(siz[v]>siz[son]) son=v; } if(siz[son]*2>=siz[x]){ res[x]=res[son]; while(siz[x]-2*siz[res[x]]>0){ res[x]=fa[res[x]]; } if(siz[x]==2*siz[res[x]]){ res1[x]=fa[res[x]]; } } } int main(){ scanf("%d",&n);mem(head,-1); rep(i,1,n-1){ int u,v;scanf("%d%d",&u,&v); add(u,v);add(v,u); } fa[1]=1; dfs(1,-1); rep(i,1,n){ if(res1[i]) printf("%d ",min(res1[i],res[i])); printf("%d\n",max(res1[i],res[i])); } }
前ICPC算法竞赛退役选手|现摸鱼ing