题意
P2195 codeforces 455c,两道一样的题
给出一个由 $n$ 个点,$m$ 条边组成的森林,有 $q$ 组询问,每次询问有以下两种情况
输入 $op = 1$ 时:给出点 $x$,输出点 $x$ 所在的树的直径。
输入 $op = 2$ 时:给出点 $x,y$,(如果 $x,y$ 在同一棵树中则忽略此操作)选择任意两点 $u,v$,使得 $u 跟 $x$ 在同一棵树中且 $v$ 跟 $y$ 在同一棵树中。将 $u,v$ 之间连一条边,使得连边后的到的新树的直径最小。
我写的代码,不加O2优化在洛谷,codeforces都能正确,但是加了O2优化10分:
评测链接
#include<bits/stdc++.h>
#define int long long
using namespace std;
int fat[600005];
int find(int x) {
return fat[x] == x?x:fat[x] = find(fat[x]);
}
int head[600005],nex[1200005],to[1200005],cnt;
int add(int x,int y) {
nex[++cnt] = head[x];
head[x] = cnt;
to[cnt] = y;
}
int n,m,q;
bool v[600005];
int maxx,ed1,ed2,root;
int deepest[600005],deepest2[600005];
void find_edge1(int now,int fa,int deep) {
for(int i = head[now];i;i = nex[i]) {
if(to[i] != fa) find_edge1(to[i],now,deep + 1);
}
if(deep >= maxx) {
maxx = deep;
ed1 = now;
}
return;
}
void find_edge2(int now,int fa,int deep) {
for(int i = head[now];i;i = nex[i]) {
if(to[i] != fa) find_edge2(to[i],now,deep + 1);
}
if(deep >= maxx) {
maxx = deep;
ed2 = now;
}
return;
}
void find_root(int now,int fa,int deep) {
if(now == ed2) {
v[now] = 1;
}
for(int i = head[now];i;i = nex[i]) {
if(to[i] != fa) {
find_root(to[i],now,deep + 1);
if(v[to[i]]) v[now] = 1;
}
}
if(v[now] and deep == maxx / 2) {
root = now;
deepest[root] = maxx - deep;
deepest2[root] = maxx / 2;
}
}
void biaoji(int now,int fa) {
for(int i = head[now];i;i = nex[i]) {
if(to[i] != fa) biaoji(to[i],now);
}
v[now] = 1;
fat[now] = root;
}
signed main() {
scanf("%lld %lld %lld",&n,&m,&q);
for(int i = 1;i <= n;i++) fat[i] = i;
while(m--) {
int x,y;
scanf("%lld %lld",&x,&y);
add(x,y),add(y,x);
}
for(int i = 1;i <= n;i++) {
if(!v[i]) {
maxx = 0;
find_edge1(i,i,0);
maxx = 0;
find_edge2(ed1,ed1,0);
find_root(ed1,ed1,0);
biaoji(ed1,ed1);
// printf("%lld %lld %lld\n",ed1,ed2,root);
}
}
for(int i = 1;i <= q;i++) {
int op,x,y;
scanf("%lld",&op);
if(op == 1) {
scanf("%lld",&x);
printf("%lld\n",deepest[find(x)] + deepest2[find(x)]);
}
if(op == 2) {
scanf("%lld %lld",&x,&y);
x = find(x),y = find(y);
if(x == y) continue;
//printf("%lld %lld\n",deepest[x],deepest[y]);
if(deepest[x] == deepest[y]) {
fat[y] = x;
deepest[x]++;
deepest2[x] = deepest[y];
}
else if(deepest[x] > deepest[y]) {
fat[y] = x;
if(deepest2[x] < deepest[y] + 1) deepest2[x] = deepest[y] + 1;
}
else {
fat[x] = y;
if(deepest2[y] < deepest[x] + 1) deepest2[y] = deepest[x] + 1;
}
}
}
return 0;
}