1. 程式人生 > >Codeforces GYM 101968 A. Tree Game

Codeforces GYM 101968 A. Tree Game

差點自閉,感謝大佬幫忙找bug

題目:https://codeforces.com/gym/101968/problem/A

找樹的重心+思維

找到樹的重心,如果重心只有一個,以重心為根節點dfs,求各節點深度,那麼任意一對節點都符合題意,只要讓先手mark深度小的節點即可,其中同樣深度的節點,交換位置扔符合題意,要加上dep[i]*(dep[i]-1)/2

如果重心有兩個,分別以兩個重心為根節點dfs,以任意一對節點都符合題意為基礎(ans=n*(n-1)/2),如果兩個深度相同的節點分別掛在兩個不同的重心上,那麼他們無法作為符合題意的一對節點,要減去這一部分,對每個重心深度相同的節點,分別加上交換節點扔符合題意的一部分,嗯就這樣

 

#include<iostream>
#include<cstdio> 
#include<cmath>
#include<queue>
#include<vector>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<set>
#include<stack>
#include<map>
#include<fstream>
#include
<cstdlib> #include<ctime> #include<list> #include<climits> #include<bitset> #include<random> using namespace std; #define fopen freopen("input.in", "r", stdin);freopen("output.in", "w", stdout); #define left asfdasdasdfasdfsdfasfsdfasfdas1 #define right asfdasdasdfasdfsdfasfsdfasfdas2 #define
y1 asfdasdasdfasdfsdfasfsdfasfdas3 typedef long long ll; typedef unsigned ui; typedef long double ld; const int dell[8][2]={{1,2},{1,-2},{2,1},{2,-1},{-1,2},{-1,-2},{-2,1},{-2,-1}}; ll mod=1e9+7; const ll inf=(1LL<<31)-1; const int maxn=1e6+7; const int maxm=1e6+7; const double eps=1e-8; const double pi=acos(-1.0); const int csize=22; int n,k,m,ar[maxn]; struct node{ int b,nex; }no[maxn*2]; int head[maxn],sz,mx,root; int pre[maxn]; ll sspre[maxn]; int pre2[maxn]; ll sspre2[maxn]; void init(){ for(int i=0;i<=n;i++)head[i]=-1; sz=0; } void add(int a,int b){ no[sz].b=b; no[sz].nex=head[a]; head[a]=sz++; } int dep[maxn],num[maxn]; void dfs(int u,int fa) { num[u]=1; if(dep[u]>mx){ mx=dep[u]; root=u; } for(int i=head[u];i!=-1;i=no[i].nex){ int v=no[i].b; if(v==fa)continue; dep[v]=dep[u]+1; dfs(v,u); num[u] += num[v]; } } bool findmid(int u,int& mid){ bool can=1; for(int i=head[u];i!=-1;i=no[i].nex){ int v=no[i].b; if(dep[v]==dep[u]+1){ if(findmid(v,mid)){ return 1; } can &= num[v]<(n+1)/2; } } if(can && num[u]>=(n+1)/2){ mid=u; return 1; } else return 0; } int main() { //fopen //freopen("input.in","r",stdin); int t;scanf("%d",&t); while(t--){ scanf("%d",&n); init(); for(int i=2;i<=n;i++){ int x;scanf("%d",&x); add(i,x); add(x,i); } mx=0;root=0; dep[1]=1; dfs(1,-1); int mid=0; findmid(1,mid); ll ans=1LL*n*(n-1)/2; if(n%2==0 && num[mid]==n/2){ int mid2=0; for(int i=head[mid];i!=-1;i=no[i].nex){ if(dep[no[i].b]+1==dep[mid]){ mid2=no[i].b; break; } } for(int i=1;i<=n;i++)dep[i]=0; dep[mid2]=1; dfs(mid2,mid); for(int i=0;i<=n+1;i++)pre[i]=pre2[i]=0; for(int i=1;i<=n;i++){ if(dep[i]>0)pre2[dep[i]]++; } for(int i=1;i<=n;i++)dep[i]=0; dep[mid]=1; dfs(mid,mid2); for(int i=1;i<=n;i++){ if(dep[i]>0){ pre[dep[i]]++; } } for(int i=1;i<=n;i++){ ans -= (ll)pre[i]*pre2[i]; } for(int i=1;i<=n;i++){ ans += (ll)pre[i]*(pre[i]-1)/2; ans += (ll)pre2[i]*(pre2[i]-1)/2; } } else{ //if(fir==1609)while(1); dep[mid]=1; dfs(mid,-1); for(int i=0;i<=n+1;i++)pre[i]=0; for(int i=1;i<=n;i++)pre[dep[i]]++; for(int i=1;i<=n;i++){ ans += (ll)pre[i]*(pre[i]-1)/2; } } printf("%lld\n",ans); } return 0; }
View Code