题意:
给出一个n个点m条边的森林,q次询问,第一种询问要求输出一个点所在树的直径,第二种询问要求合并两个点所在的树。
思路:
先将初始的森林中各个树的直径求出来,然后用并查集维护。两树合并时,设直径分别为len1,len2,新树直径为max(len1,len2,(len1/2)+(len2/2)+(len1%2)+(len2%2)+1),即两颗旧树的直径,两颗旧树直径的一半向上取整加一,中的较大值。
优化上可以用并查集路径压缩+启发式合并,输入挂。
代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <map>
#include <list>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <sstream>
#define pb push_back
#define X first
#define Y second
#define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin())
#define pii pair<int,int>
#define qclear(a) while(!a.empty())a.pop();
#define lowbit(x) (x&-x)
//#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d%d",&n,&m)
#define sddd(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define mst(a,b) memset(a,b,sizeof(a))
#define cout3(x,y,z) cout<<x<<" "<<y<<" "<<z<<endl
#define cout2(x,y) cout<<x<<" "<<y<<endl
#define cout1(x) cout<<x<<endl
#define IOS std::ios::sync_with_stdio(false)
#define SRAND srand((unsigned int)(time(0)))
typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
using namespace std;
const double PI=acos(-1.0);
const int INF=0x3f3f3f3f;
const ll mod=998244353;
const double eps=1e-8;
const int maxn=300005;
const int maxm=10005;
template<class T>
inline bool sd(T &ret){
char c;
int sgn;
if(c=getchar(),c==EOF)return 0;
while(c!='-'&&(c<'0'||c>'9'))c=getchar();
sgn=(c=='-')?-1:1;
ret=(c=='-')?0:(c-'0');
while(c=getchar(),c>='0'&&c<='9')ret=ret*10+(c-'0');
ret*=sgn;
return 1;
}
inline void out(int x){
if(x>9)out(x/10);
putchar(x%10+'0');
}
int n,m,q;
vector<int>maps[maxn];
int fa[maxn];
int rk[maxn];
inline void init(){
for(int i=0;i<=n;i++){
fa[i]=i;
rk[i]=1;
}
}
inline int findfa(int x){
return fa[x]==x?x:fa[x]=findfa(fa[x]);
}
inline void meg(int a,int b){
int f1,f2;
f1=findfa(a);
f2=findfa(b);
if(rk[f1]<rk[f2]){
fa[f1]=f2;
rk[f2]+=rk[f1];
}else{
fa[f2]=f1;
rk[f1]+=rk[f2];
}
return ;
}
int lens[maxn];
bool vis[maxn];
int maxlen=0;
int mark=-1;
inline void dfs(int u,int d){
vis[u]=1;
if(d>maxlen){
maxlen=d;
mark=u;
}
for(int i=0;i<maps[u].size();i++){
int v=maps[u][i];
if(!vis[v]){
dfs(v,d+1);
}
}
vis[u]=0;
}
inline void callens(int now){
maxlen=0;
mark=-1;
dfs(now,0);
dfs(mark,0);
lens[now]=maxlen;
}
void solve() {
sd(n);
sd(m);
sd(q);
init();
for(int i=0;i<m;i++){
int u,v;
sd(u);
sd(v);
maps[u].pb(v);
maps[v].pb(u);
meg(u,v);
}
mst(lens,0);
mst(vis,0);
for(int i=1;i<=n;i++){
int now=findfa(i);
if(lens[now]==0){
callens(now);
}
}
for(int qq=0;qq<q;qq++){
int op,u,v;
sd(op);
if(op==1){
sd(u);
out(lens[findfa(u)]);
putchar('\n');
}else{
sd(u);
sd(v);
if(findfa(u)==findfa(v))continue;
int len1,len2,len3;
len1=lens[findfa(u)];
len2=lens[findfa(v)];
len3=(len1>>1)+(len2>>1)+(len1&1)+(len2&1)+1;
meg(u,v);
lens[findfa(u)]=max(len1,max(len2,len3));
}
}
return ;
}
int main() {
#ifdef LOCAL
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#else
// freopen("","r",stdin);
// freopen("","w",stdout);
#endif
solve();
return 0;
}