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");
// }
}