Hdu-6200 mustedge mustedge mustedge(动态树+并查集)

本文介绍了一种处理动态无向图中桥边查询的方法,通过并查集和LCT维护图的变化,实现高效地计算两个节点间必须经过的桥边数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Give an connected undirected graph with n nodes and m edges, (n,m105) which has no selfloops or multiple edges initially.
Now we have q operations (q105):
  
1 u v: add an undirected edge from u to v; (uv&&1u,vn)
2 u v: count the number of mustedges from u to v; (1u,vn).

mustedge: we define set Ei as a path from u to v which contain edges in this path, and |k1Ei| is the number of mustedges. |x| means size of set x, and E1,E2Ek means all the paths.
It's guaranteed that n,m,q106

Please note that maybe there are more than one edges between two nodes after we add edges. They are not the same, which means they can be in a set at the same time. Read the sample data for more information.
Input
Input starts with an integer T, denoting the number of test cases.
For each case:
First line are two number n and m;
Then next m lines, each contains two integers u and v, which indicates an undirected edge from u to v;
Next line contains a number q, the number of operations;
Then next q lines, contains three integers x, u and v where x
is the operation type, which describes an operation.

Output
For each test case, output "Case #x:" where x is the test case number starting from 1.
In each test case, print a single number one line when query the number of mustedges
.
Sample Input
2
4 3
1 2
2 3
3 4
5
2 1 4
1 2 3
2 1 4
2 2 3
2 2 4
8 9
1 2
2 3
1 3
3 4
4 5
4 6
5 7
5 8
7 8
5
2 7 8
2 1 6
2 4 7
1 6 8
2 5 6
Sample Output
Case #1:
3
2
0
1
Case #2:
0
2
1
0

题意:大概就是给你一个图,可以动态加边,每次询问从u到v要经过几个桥边,还是一样的套路,用并查集+LCT动态维护缩点后的树,有点卡常,加了fread才过了。

#include <queue>
#include <cstdio>
#include <cstring> 
#include <iostream>
#define INF 2147483640
#define eps 1e-9
using namespace std;
const int MAXN = 2e5 + 10;
int n,m,q,f[MAXN],f2[MAXN],s[MAXN],ch[MAXN][2],val[MAXN],sum[MAXN],fa[MAXN];
bool lazy[MAXN];
inline int nextChr()
{
    static const int siz=1<<22;
    static char buf[siz],*chr=buf+siz;
    if(chr==buf+siz)fread(chr=buf,1,siz,stdin);
    return int(*chr++);
}
inline int read()
{
    register int r=0,c=nextChr();
    for(;c<48;c=nextChr());
    for(;c>47;c=nextChr())r=(r<<3)+(r<<1)+c-48;
    return r;
}    
inline int Find(int x)
{
	if(f[x] == x) return x;
	f[x] = Find(f[x]);
	return f[x];
}
inline int Find2(int x)
{
	if(f2[x] == x) return x;
	f2[x] = Find2(f2[x]);
	return f2[x];
}
inline bool isroot(int x)
{
	return ch[Find(fa[x])][0] != x && ch[f[fa[x]]][1] != x;
}
void push_up(int x)
{
	int ls = ch[x][0],rs = ch[x][1];
	sum[x] = sum[ls] + sum[rs] + val[x]; 
}
void rotate(int x)
{
	int y = Find(fa[x]),z = Find(fa[y]);
	int d = ch[y][0] == x ? 0 : 1;
	if(!isroot(y))
	{
		if(ch[z][0] == y) ch[z][0] = x;
		else ch[z][1] = x;
	}
	fa[y] = x,fa[x] = z;fa[ch[x][d^1]] = y;
	ch[y][d] = ch[x][d^1],ch[x][d^1] = y;
	push_up(y),push_up(x);
}
inline void push_down(int x)
{
	if(!lazy[x]) return;
	int ls = ch[x][0],rs = ch[x][1];
	lazy[x] ^= 1;lazy[ls] ^= 1;lazy[rs] ^= 1;
	swap(ch[ls][0],ch[ls][1]);
	swap(ch[rs][0],ch[rs][1]);
}
void splay(int x)
{
	int tot = 0;s[++tot] = x;
	for(int i = x;!isroot(i);i = Find(fa[i])) s[++tot] = Find(fa[i]);
	for(;tot;tot--) push_down(s[tot]);
	while(!isroot(x))
	{
		int y = Find(fa[x]),z = Find(fa[y]);
		if(!isroot(y))
		{
			if((ch[z][0] == y) ^ (ch[y][0] == x)) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
}
void access(int x)
{
	int t = 0;
	while(x)
	{
		splay(x);
		ch[x][1] = t;
		push_up(x);
		t = x,x = Find(fa[x]);
	}
}
void makeroot(int x)
{
	access(x),splay(x);
	swap(ch[x][0],ch[x][1]);
	lazy[x] ^= 1;
}
void link(int x,int y)
{
	makeroot(x);fa[x] = y;
	f2[f2[x]] = y;
}
bool linked(int x,int y)
{
	return Find2(x) == Find2(y);
}
void rebuild(int x,int y)
{
	if(!x) return;
	f[f[x]] = y;
	rebuild(ch[x][0],y);
	rebuild(ch[x][1],y);
}
int main()
{
	int T = read();
	for(int Time = 1;Time <= T;Time++)
	{
		printf("Case #%d:\n",Time);
		n = read(),m = read();
		for(int i = 1;i <= 2*n;i++) f[i] = f2[i] = i,fa[i] = ch[i][0] = ch[i][1] = lazy[i] = 0;
		for(int i = 1;i <= n;i++) val[i] = sum[i] = 1;
		for(int i = 1;i <= m;i++)
		{
			int x = read(),y = read();
			if(!linked(Find(x),Find(y))) link(f[x],f[y]);
			else 
			{
				if(f[x] == f[y]) continue;
				makeroot(f[x]);
				access(f[y]);
				splay(f[y]);
				++n;
				val[n] = sum[n] = 1;
				f2[n] = f2[f[y]];
				rebuild(f[y],n);
			}
		}
		q = read();
		while(q--)
		{
			int p,x,y;
			p = read(),x = read(),y = read();
			if(p == 1)
			{
				if(!linked(Find(x),Find(y))) link(f[x],f[y]);
				else 
				{
					if(f[x] == f[y]) continue;
					makeroot(f[x]);
					access(f[y]);
					splay(f[y]);
					++n;
					val[n] = sum[n] = 1;
					f2[n] = f2[f[y]];
					rebuild(f[y],n);
				}
			}
			if(p == 2)
			{
				if(!linked(Find(x),Find(y))) printf("0\n");
				else 
				{
					makeroot(f[x]);
					access(f[y]);
					splay(f[y]);
					printf("%d\n",sum[f[y]]-1);
				}
			}
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值