题意: 给定一颗树, 问删除几条边可以使每个连通块内的个数都相同,输出合法的可删除的边数。
日常统计子树大小,顺便标一下。
如果我要统计每个块中点的个数是x的话 我需要统计块中点的个数是x的个数,我就需要统计 k*x (k *x<= n)出现的次数。
至于为什么,画个树形图感受一下吧
#include <bits/stdc++.h>
#define ms(x) memset(x, 0, sizeof(x))
#define ll long long
using namespace std;
const int N = 1000000 + 10, M = 1000000 + 10, INF = 0x3f3f3f3f;
struct node{
int v;
node(int x):v(x){}
};
vector<node>E[N];
void addedge(int u, int v){
E[u].push_back(v);
E[v].push_back(u);
}
int n, m;
int q[N];
int in[N];
int dfs(int fa, int x){
q[x] = 1;
for(int i=0;i<E[x].size();i++){
int v = E[x][i].v;
if(v == fa) continue;
q[x] = q[x] + dfs(x, v);
}
in[q[x]]++;
return q[x];
}
bool check(int x){
int sum = 0;
for(int i=x;i<=n;i+=x){
sum += in[i];
}
// if(sum == n/x) return 1
return sum==(n/x);
}
int main()
{
ms(in);
scanf("%d", &n);
for(int i=0;i<n-1;i++){
int u, v;
scanf("%d%d",&u,&v);
addedge(u, v);
}
dfs(-1, 1);
vector<int>ans;
ans.push_back(n-1);
for(int i=2;i<=(int)sqrt(n);i++){
if(n%i==0){
if(check(i))
ans.push_back(n/i - 1);
if(check(n/i))
ans.push_back(i-1);
}
}
sort(ans.begin(), ans.end());
for(int i=0;i<ans.size();i++){
if( i) printf(" ");
printf("%d",ans[i]);
}
return 0;
}