Give an connected undirected graph with
n
nodes and
m
edges, (n,m≤105)
which has no selfloops or multiple edges
initially.
Now we have q operations (q≤105):
⋅1 u v: add an undirected edge from u to v; (u≠v&&1≤u,v≤n)
⋅2 u v: count the number of mustedges from u to v; (1≤u,v≤n).
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,E2…Ek means all the paths.
It's guaranteed that ∑n,∑m,∑q≤106
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
Sample Output
Now we have q operations (q≤105):
⋅1 u v: add an undirected edge from u to v; (u≠v&&1≤u,v≤n)
⋅2 u v: count the number of mustedges from u to v; (1≤u,v≤n).
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,E2…Ek means all the paths.
It's guaranteed that ∑n,∑m,∑q≤106
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.
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
In each test case, print a single number one line when query the number of mustedges
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
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);
}
}
}
}
}