题意:
给定一颗树,要求用 刀将树切成等大小的 块,问 有哪些可能取值。将所有可能取值输出。
思路:
这个问题一开始看到有点懵,我们可以将其进行转化,先考虑比较简单的情况。
如果要求用 刀把树切成等块,问你是否可能?这个问题就比较容易考虑,如果某一个节点的子树大小刚好为 ,则这个节点连向父节点的边是一定要切的,因此我们暴力切树即可。
然后可以发现,如果某个节点的子树大小为 的倍数,那么这个节点连向父节点的边是一定要切的。因此我们统计子树大小为 倍数的个数。如果这个个数恰好等于 ,则说明可以用 刀对树进行划分,否则不能。
因此我们用一个 来记录, 表示有多少个节点的子树大小为 ,然后枚举每一个 ,进行判断即可。
代码:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define rep(i,a,b) for(int i = a; i <= b; i++)
#define LOG1(x1,x2) cout << x1 << ": " << x2 << endl;
#define LOG2(x1,x2,y1,y2) cout << x1 << ": " << x2 << " , " << y1 << ": " << y2 << endl;
typedef long long ll;
typedef double db;
const db EPS = 1e-9;
using namespace std;
const int N = 1e6+1000;
int tot,head[N],n,vis[N],siz[N];
struct Edge{
int to,next;
}e[2*N];
void add(int x,int y){
e[++tot].to = y, e[tot].next = head[x], head[x] = tot;
}
void dfs(int x,int pre){
siz[x]++;
for(int i = head[x]; i; i = e[i].next){
int y = e[i].to;
if(y == pre) continue;
dfs(y,x);
siz[x] += siz[y];
}
vis[siz[x]]++;
}
bool solve(int k)
{
int cnt = 0;
if(n % (k+1)) return 0;
int s = n/(k+1);
while(s <= n){
if(vis[s]) cnt+=vis[s];
s += n/(k+1);
}
//LOG2("cnt",cnt,"k",k);
return cnt == (k+1);
}
int main()
{
tot = 0;
scanf("%d",&n);
rep(i,1,n-1){
int x,y;
scanf("%d%d",&x,&y);
add(x,y), add(y,x);
}
dfs(1,0);
rep(i,1,n){
if(solve(i)) printf("%d ",i);
}
return 0;
}