codeforces 765E

codeforces 765E

题目描述

anya wants to minimize a tree. He can perform the following operation multiple times: choose a vertex v, and two disjoint (except for v) paths of equal length a0 = v, a1, …, ak, and b0 = v, b1, …, bk. Additionally, vertices a1, …, ak, b1, …, bk must not have any neighbours in the tree other than adjacent vertices of corresponding paths. After that, one of the paths may be merged into the other, that is, the vertices b1, …, bk can be effectively erased.Help Vanya determine if it possible to make the tree into a path via a sequence of described operations, and if the answer is positive, also determine the shortest length of such path.

大意

从一个节点每次可以合并两条长度一样的链(直链且不含其他支链),问最后如果能变成一条直链的话,最短长度是多少。

解法

选择直径的中点为根,进行合并。对于根节点,不同的连接根的子树的深度最多只能出现两种值。而对于其他节点,其子树必须满足深度相同。

#include<bits/stdc++.h>

using namespace std;

const int SIZE = 200005;
typedef long long ll;

vector<int> g[SIZE];

int len = 0;
int v1 = 1;
void dfs1(int u, int d, int fa) {
    if(d >= len) {
        len = d;
        v1 = u;
    }
    for(int v: g[u]) {
        if(v == fa) continue;
        dfs1(v, d + 1, u);
    }
}

int l2 = 0;
int v2 = 1;
int pre[SIZE];
void dfs2(int u, int d, int fa) {
    pre[u] = fa;
    if(d >= l2) {
        l2 = d;
        v2 = u;
    }
    for(int v: g[u]) {
        if(v == fa) continue;
        dfs2(v, d + 1, u);
    }
}
int c;
bool dfs3(int u, int fa, int d) {
    int cnt = 0;
    bool res = true;
    for(int v: g[u]) {
        if(v == fa) continue;
        cnt++;
        res = res && dfs3(v, u, d + 1);
    }
    if(!cnt) {
        if(d!=l2/2) return false;
    }
    return res;
}

int dfs4(int u, int fa, int d) {
    bool gg = false;
    int last = -1;
    for(int v: g[u]) {
        if(v == fa) continue;
        int t = dfs4(v, u, d + 1);
        if(t == -1) return -1;
        if(last == -1) {
            last = t;
        }
        else {
            if(t != last) return -1;
        }
    }
    if(last == -1) return 1;
    //printf("u=%d res=%d\n",u,last+1);
    return last + 1;
}

int main() {
    int n;
    scanf("%d",&n);
    for(int i = 1; i < n; i++) {
        int a, b;
        scanf("%d%d",&a,&b);
        g[a].push_back(b);
        g[b].push_back(a);
    }
    dfs1(1, 0, -1);
    dfs2(v1, 0, -1);


    int t = l2 / 2;
    int d = t;
    c = v2;
    if(l2 % 2 == 1) {
        while(t--) c = pre[c];//printf("v1=%d v2=%d c=%d\n",v1,v2,c);
   // if(dfs3(c, -1, 0)) {
    //    while(d % 2 == 0) d /= 2;
   //     printf("%d\n",d);
   // }
   // else {

        set<int> S;
        int gg = 0;
        for(int u: g[c]) {
            int t = dfs4(u, c, 0);
            //printf("--------u=%d t=%d\n",u,t);
            if(t == -1) {
                gg = 1;
                break;
            }
            S.insert(t);
            if(S.size() > 2) {
                gg = 1;
                break;
            }
        }
        if(!gg)
        if(S.size() > 2) {
            gg = 1;
        }
        else if(S.size() == 1) {
            int dd = 0;
            for(int ddd: S) dd += ddd;
            //printf("dd=%d\n",dd);
            while(dd % 2 == 0) dd /= 2;
            printf("%d\n",dd);
        }
        else {
            int dd = 0;
            for(int ddd: S) dd += ddd;
            //printf("dd=%d\n",dd);
            while(dd % 2 == 0) dd /= 2;
            printf("%d\n",dd);
        }
        if(gg) {
            if(gg) printf("-1");
        }
        return 0;
    }
    while(t--) c = pre[c];//printf("v1=%d v2=%d c=%d\n",v1,v2,c);
   // if(dfs3(c, -1, 0)) {
    //    while(d % 2 == 0) d /= 2;
   //     printf("%d\n",d);
   // }
   // else {

        set<int> S;
        int gg = 0;
        for(int u: g[c]) {
            int t = dfs4(u, c, 0);
            //printf("--------u=%d t=%d\n",u,t);
            if(t == -1) {
                gg = 1;
                break;
            }
            S.insert(t);
            if(S.size() > 2) {
                gg = 1;
                break;
            }
        }
        if(!gg)
        if(S.size() > 2) {
            gg = 1;
        }
        else if(S.size() == 1) {
            int dd = 0;
            for(int ddd: S) dd += ddd;
            //printf("dd=%d\n",dd);
            while(dd % 2 == 0) dd /= 2;
            printf("%d\n",dd);
        }
        else {
            int dd = 0;
            for(int ddd: S) dd += ddd;
            //printf("dd=%d\n",dd);
            while(dd % 2 == 0) dd /= 2;
            printf("%d\n",dd);
        }
        if(gg) printf("-1\n");
   // }


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值