Problem Description
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.
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.
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 .
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
Source
赛场上想到了树剖的方法,听说过不去就没有写
这题单log的做法是并查集+LCA+树状数组
我们先预处理出一棵生成树
假设加的边为(u,v)
那么我们找到u,v的LCA x
将u到x和v到x两条链上的边给标记
每次标记的时候把子树的深度减1
然后用并查集维护标记过的边的集合,这样每条边都只会被标记一遍
查询答案(u,v)的时候就是dep[u]+dep[v]-dep[x]*2,其中x是u,v的LCA
稍微有点卡常,找LCA的地方建议用树剖来写
因为边集和点集是同一个数量级
所以不建议先缩点再进行操作
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
inline char nc(){
// static char buf[6000000],*p1=buf,*p2=buf;
// return p1==p2&&(p2=(p1=buf)+fread(buf,1,6000000,stdin),p1==p2)?EOF:*p1++;
return getchar();
}
inline int read(){
char ch=nc();int sum=0;
while(!(ch>='0'&&ch<='9'))ch=nc();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
return sum;
//int x;
//scanf("%d",&x);
//return x;
}
struct line
{
int s,t;
int next;
}a[200001];
int edge,exedge;
int head[100001];
int scc,cnt;
bool v[100001];
int s[100001],topx;
int fa[100001];
inline void add(int s,int t)
{
a[edge].next=head[s];
head[s]=edge;
a[edge].s=s;
a[edge].t=t;
}
int tot;
int ld[100001],rd[100001];
int fax[100001];
int dep[100001],son[100001];
int top[100001],w[100001];
int lson[100001]/*最大节点位置*/,mson[100001]/*最大节点值*/;
inline void dfs1(int d)
{
v[d]=true;
mson[d]=0;
son[d]=0;
int i;
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(!v[t])
{
dep[t]=dep[d]+1;
fa[t]=d;
dfs1(t);
son[d]+=son[t]+1;
if(son[t]>=mson[d])
{
mson[d]=son[t];
lson[d]=t;
}
}
}
}
inline void dfs2(int d)//先dfs重链
{
v[d]=true;
tot++;
w[tot]=d;
ld[d]=tot;
int i;
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(t==lson[d]&&!v[t])
{
top[t]=top[d];
dfs2(t);
}
}
for(i=head[d];i!=0;i=a[i].next)
{
int t=a[i].t;
if(!v[t]&&t!=lson[d])
{
top[t]=t;
dfs2(t);
}
}
rd[d]=tot;
}
inline int lca(int s,int t)//深的那个点往当前链的top跳
{
int u=top[s],v=top[t];
while(u!=v)
{
if(dep[u]>dep[v])
s=fa[top[s]];
else
t=fa[top[t]];
u=top[s];
v=top[t];
}
if(ld[s]<ld[t])
return s;
else
return t;
}
int tr[100005];
inline int lowbit(int x)
{
return x&(-x);
}
inline void addx(int x,int xx)
{
int i;
for(i=x;i<=n;i+=lowbit(i))
tr[i]+=xx;
}
inline int ask(int x)
{
int i,sum=0;
for(i=x;i>=1;i-=lowbit(i))
sum+=tr[i];
return sum;
}
inline int findx(int x)
{
if(fax[x]!=x)
fax[x]=findx(fax[x]);
return fax[x];
}
inline void change(int s,int t)
{
s=findx(s);
int lx=fa[s];
while(dep[lx]>=dep[t])
{
addx(ld[s],-1);
addx(rd[s]+1,1);
//fa[s]=lx;
fax[s]=lx;
s=findx(lx);
lx=fa[s];
// assert(s!=lx);
}
}
int ss[100001],tt[100001];
bool vv[100001];
int main()
{
//freopen("1007.in","r",stdin);
// freopen("1007.out","w",stdout);
int T,kk=0;
//scanf("%d",&T);
T=read();
while(T>0)
{
kk++;
T--;
int m;
//scanf("%d%d",&n,&m);
// assert(T>=5);
n=read();
m=read();
int i;
int s,t;
edge=0;
memset(head,0,sizeof(head));
for(i=1;i<=m;i++)
{
//scanf("%d%d",&s,&t);
ss[i]=read();
tt[i]=read();
}
for(i=1;i<=n;i++)
fax[i]=i;
int sum=0;
memset(vv,false,sizeof(vv));
for(i=1;i<=m;i++)
{
int fx=findx(ss[i]),fy=findx(tt[i]);
if(fx!=fy)
{
sum++;
fax[fx]=fy;
edge++;
add(ss[i],tt[i]);
edge++;
add(tt[i],ss[i]);
vv[i]=true;
if(sum==n-1)
break;
}
}
tot=0;
memset(v,false,sizeof(v));
memset(fa,0,sizeof(fa));
dep[1]=1;
dfs1(1);
memset(v,false,sizeof(v));
dfs2(1);
memset(tr,0,sizeof(tr));
for(i=1;i<=n;i++)
fax[i]=i;
for(i=1;i<=m;i++)
{
if(!vv[i])
{
int lx=lca(ss[i],tt[i]);
change(ss[i],lx);
change(tt[i],lx);
}
}
int q;
//scanf("%d",&q);
q=read();
int x;
printf("Case #%d:\n",kk);
for(i=1;i<=q;i++)
{
//scanf("%d%d%d",&x,&s,&t);
x=read();
s=read();
t=read();
if(x==1)
{
int lx=lca(s,t);
change(s,lx);
change(t,lx);
}
else
{
int lx=lca(s,t);
int dep1=dep[lx]+ask(ld[lx]);
int dep2=dep[s]+ask(ld[s]);
int dep3=dep[t]+ask(ld[t]);
printf("%d\n",dep2+dep3-dep1*2);
}
}
}
return 0;
}