codeforces 455C 并查集

传送门

给n个点, 初始有m条边, q个操作。

每个操作有两种, 1是询问点x所在的连通块内的最长路径, 就是树的直径。 2是将x, y所在的两个连通块连接起来,并且要合并之后的树的直径最小,如果属于同一个连通块就忽视这个操作。

先dfs出每个连通块的初始直径, 然后合并的话就是len[x] = max( (len[x]+1)/2+(len[y]+1)/2+1, max(len[x], len[y]));  然后搞一搞就好了。

一开始写bfs写挫了一直超时,  只好改成dfs......

 #include<bits/stdc++.h>
using namespace std;
#define pb(x) push_back(x)
#define ll long long
#define mk(x, y) make_pair(x, y)
#define lson l, m, rt<<1
#define mem(a) memset(a, 0, sizeof(a))
#define rson m+1, r, rt<<1|1
#define mem1(a) memset(a, -1, sizeof(a))
#define mem2(a) memset(a, 0x3f, sizeof(a))
#define rep(i, a, n) for(int i = a; i<n; i++)
#define ull unsigned long long
typedef pair<int, int> pll;
const double PI = acos(-1.0);
const double eps = 1e-;
const int mod = 1e9+;
const int inf = ;
const int dir[][] = { {-, }, {, }, {, -}, {, } };
const int maxn = 3e5+;
int f[maxn], num[maxn], head[maxn*], dis[maxn], cnt, q[maxn*];
struct node
{
int to, nextt;
}e[maxn*];
void add(int u, int v) {
e[cnt].to = v;
e[cnt].nextt = head[u];
head[u] = cnt++;
}
int findd(int u) {
return f[u] == u?u:f[u] = findd(f[u]);
}
void unionn(int x, int y) {
x = findd(x);
y = findd(y);
if(x == y)
return ;
f[y] = x;
int now = (+num[x])/+(num[y]+)/+;
num[x] = max(now, max(num[x], num[y]));
}
int maxx = , pos = -;
int dfs(int u, int fa, int d) {
if(d>maxx) {
maxx = d;
pos = u;
}
for(int i = head[u]; ~i; i = e[i].nextt) {
int v = e[i].to;
if(v == fa)
continue;
dfs(v, u, d+);
}
}
template<typename __ll>
inline void read(__ll &m)
{
__ll x=,f=;char ch=getchar();
while(!(ch>=''&&ch<='')){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
m=x*f;
}
int main()
{
int n, m, q, x, y;
cin>>n>>m>>q;
mem1(head);
for(int i = ; i<=n; i++) {
f[i] = i;
num[i] = ;
}
while(m--) {
read(x); read(y);
add(x, y);
add(y, x);
x = findd(x); y = findd(y);
f[x] = y;
}
for(int i = ; i<=n; i++) {
if(f[i] == i) {
dfs(i, -, );
maxx = ;
if(pos == -)
continue;
dfs(pos, -, );
num[i] = maxx;
maxx = ;
pos = -;
}
}
while(q--) {
int sign;
read(sign);
if(sign == ) {
read(x);
printf("%d\n", num[findd(x)]);
} else {
read(x); read(y);
unionn(x, y);
}
}
}
上一篇:双端队列(单调队列)poj2823 区间最小值(RMQ也可以)


下一篇:June 5. 2018 Week 23rd Tuesday