GYM - 101620 J.Justified Jungle

题意:

  给出一棵树,删掉其中一些边,要求生成的每个子树节点数一样。输出所有可以删掉的边数。

题解:

  以节点1为根,预处理每个子树的大小。对于每个n的因数x,还需满足子树为他倍数的点够n/x个,那么删的边数就为n/x-1。

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int n;
int u, v;
int sz[N], vis[N];
int tot;
int head[N], point[N<<1], nxt[N<<1]; 
vector<int> ans;
void add_edge(int u, int v) {
    point[++tot] = v;
    nxt[tot] = head[u];
    head[u] = tot;
}
void dfs(int u, int pre) {
    sz[u] = 1;
    for(int i = head[u]; i; i = nxt[i]) {
        if(point[i]==pre) continue;
        dfs(point[i], u);
        sz[u] += sz[point[i]];
    }
    vis[sz[u]]++;
}
bool check(int x) {
    int cnt = 0;
    for(int i = x; i <= n; i+=x) cnt += vis[i];
    return cnt==n/x;
}
int main() {
    scanf("%d", &n);
    ans.push_back(n-1);
    for(int i = 1; i < n; i++) {
        scanf("%d%d", &u, &v);
        add_edge(u, v);
        add_edge(v, u);
    }
    dfs(1, 0);
    int up = sqrt(n);
    for(int i = 2; i <= up; i++) {
        if(!(n % i)) {
            if(check(i)) ans.push_back(n/i-1);
            if(i*i!=n && check(n/i)) ans.push_back(i-1);
        }
    }
    sort(ans.begin(), ans.end());
    int len = ans.size();
    for(int i = 0; i < len; i++) {
        printf("%d", ans[i]);
        if(i!=len-1) printf(" ");
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/Pneuis/p/9029274.html