【树的直径+并查集】 codeforces 455C - Civilization

先预处理出每个集合的最长路,就是树的直径,可以两次BFS找。。然后合并集合更新最长路就是在dep[a],dep[b],(dep[a]+1)/2+(dep[b]+1)/2+1三者取最大。。

#include <iostream>  
#include <queue>  
#include <stack>  
#include <map>  
#include <set>  
#include <bitset>  
#include <cstdio>  
#include <algorithm>  
#include <cstring>  
#include <climits>  
#include <cstdlib>
#include <cmath>
#include <time.h>
#define maxn 300005
#define maxm 100005
#define eps 1e-10
#define mod 3
#define INF 1e9
#define lowbit(x) (x&(-x))  
#define ls o<<1
#define rs o<<1 | 1
#define lson o<<1, L, mid  
#define rson o<<1 | 1, mid+1, R  
typedef long long LL;
//typedef int LL;
using namespace std;

int n, m;
int f[maxn], dep[maxn];
vector<int> vec[maxn];
vector<int> g[maxn];
set<int> s[maxn];
queue<int> q;
int vis[maxn];
int dis[maxn];

int find(int x)
{
	return x == f[x] ? x : f[x] = find(f[x]);
}

void debug(void)
{
	for(int i = 1; i <= n; i++)
		printf("AA  %d  BB\n", dep[i]);
}
int bfs(int u)
{
	int d = g[f[u]].size(), mx;
	for(int i = 0; i < d; i++) dis[g[f[u]][i]] = INF;
	q.push(u), dis[u] = 0, mx = u;
	while(!q.empty()) {
		int x = q.front();
		q.pop();
		int d = vec[x].size();
		for(int i = 0; i < d; i++) {
			if(dis[vec[x][i]] > dis[x] + 1) {
				dis[vec[x][i]] = dis[x] + 1;
				q.push(vec[x][i]);
				if(dis[vec[x][i]] > dis[mx])
					mx = vec[x][i];
			}
		}
	}
	return mx;
}
void init(void)
{
	int q, u, v, aa, bb;
	scanf("%d%d%d", &n, &m, &q);
	for(int i = 0; i <= n; i++) f[i] = i;
	while(m--) {
		scanf("%d%d", &u, &v);
		vec[u].push_back(v);
		vec[v].push_back(u);
		aa = find(u);
		bb = find(v);
		if(aa == bb) continue;
		else if(aa < bb) f[bb] = aa;
		else f[aa] = bb;
	}
	m = q;
	for(int i = 1; i <= n; i++) find(i);
	for(int i = 1; i <= n; i++) {
		s[f[i]].insert(i);
		g[f[i]].push_back(i);
	}
	for(int i = 1; i <= n; i++) {
		if(f[i] == i) {
			int tmp = bfs(i);
			tmp = bfs(tmp);
			dep[i] = dis[tmp];
		}
	}
}
void work(void)
{
	int k, a, b, aa, bb;
	while(m--) {
		scanf("%d", &k);
		if(k == 1) {
			scanf("%d", &a);
			aa = find(a);
			printf("%d\n", dep[aa]);
		}
		else {
			scanf("%d%d", &a, &b);
			aa = find(a);
			bb = find(b);
			if(aa == bb) continue;
			int tmp = (dep[aa] + 1)/2 + (dep[bb] + 1)/2 + 1;
			tmp = max(tmp, max(dep[aa], dep[bb]));
			if(aa > bb) f[aa] = bb, dep[bb] = tmp;
			else f[bb] = aa, dep[aa] = tmp;
		}
	}
}
int main(void)
{
	init();
	work();
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值