题意:给你n个点,m条边,两种操作:
- 1 u v 把u v之间的边删掉一个
2 u v 如果删除一条边就能使u,v不连通,那么找出所有满足这个条件的这些边的个数。
注意:每一个时刻都保证图是一个连通图,可能有重边,可能有自环(u-u这种边)
删边这种东西太难处理,所以我们离线做,找出终图,然后加边,加边这种东西用并查集就可以维护,关键我们怎么求操作2?
1:很明显,我们要把所有的边的双连通分量缩成一个点来看终图,这样,终图变成了一棵树。
2:对于一棵树:执行操作2的意思就是找u->v的路径的长度,即找lca(u,v)。但是这里有一个问题:如果每次都在logn的操作内找到lca(u,v),并且因为有重边,所以如果一条树边有重边的话,那么这条边就不能算满足条件的边。
3:我们给每条边一个边权(就是终图的时候u-v这条边的数量),那么我们要求的就是u->lca(u,v)->v条路径上面所有的边权为1的边的数量。这个时候我们想到用线段树来维护答案。到这里我们操作2搞定了,那么操作1怎么搞?
4:操作1是加边,这里要分两种情况:
(1):如果u,v是一个连通分量里面的,那么我们可以不需要操作
(2):如果不是一个联通分量里面的,那么此时u->lca(u,v)->v这个图形成了一个新的双连通分量,如果我们再把这个连通分量缩成一个点,那么所有与这个联通分量有关的边都得重新进行连接(还是有点麻烦的)。我们换一种思考方式:我们用线段树来维护答案的话,那么u->lca(u,v)->v这条边的权值都付成0,是不是就可以了?很明显是对的。然后操作1就变成了一个树链剖分后的线段树的一个区间修改操作。
5:我们加边的时候没有进行缩点的好处就是你可以保证终图永远不会改变,用一棵线段树的就可以维护所有的操作。
当然这个是赛后AC的,比赛的时候看了这题,想了一会没什么思路,放弃去搞别的题了
由于本弱的代码能力实在捉急,所以这道题又写了好长。。。
#include <bits/stdc++.h>
#define LL long long
#define FOR(i,x,y) for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define INF 0x3fffffff
#define N 33000
#define Q 100010
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define lrt rt<<1
#define rrt rt<<1|1
using namespace std;
int n,m,q;
typedef pair<int,int> pii;
map <pii,int> st;
vector <int> G[N];
stack <int> s;
int pos[N],dfn[N],dfs_clock,low[N],num[N];
void dfs(int u,int fa){
dfn[u] = low[u] = ++dfs_clock;
s.push(u);
FOR(i,0,G[u].size()){
int v = G[u][i];
if(!dfn[v]){
dfs(v,u);
low[u] = min(low[u],low[v]);
}
else if(v != fa){
low[u] = min(dfn[v],low[u]);
}
}
if(low[u] == dfn[u]){
int cnt = 0,minx = INF;
while(!s.empty()){
num[cnt++] = s.top();
minx = min(minx,num[cnt-1]);
s.pop();
if(num[cnt-1] == u) break;
}
FOR(i,0,cnt){
pos[num[i]] = minx;
}
}
}
struct Eedge{
int type;
int u,v;
Eedge() {}
Eedge(int t,int x,int y) : type(t),u(x),v(y) {}
bool operator < (const Eedge& rhs) const{
if(u == rhs.u && v == rhs.v) return type < rhs.type;
if(u == rhs.u) return v < rhs.v;
return u < rhs.u;
}
}eedge[Q<<1];
int eedge_cnt;
struct Commends{
int op;
int u,v;
Commends() {}
Commends(int opp,int uu,int vv) : op(opp),u(uu),v(vv) {}
}cmd[Q];
void init(){
eedge_cnt = 0;
FOR(i,0,m){
int u,v;
scanf("%d%d",&u,&v);
if(u == v) continue;
if(u < v) eedge[eedge_cnt++] = Eedge(0,u,v);
else eedge[eedge_cnt++] = Eedge(0,v,u);
}
FOR(i,0,q){
int op,u,v;
scanf("%d%d%d",&op,&u,&v);
cmd[i] = Commends(op,u,v);
if(u == v) continue;
if(u < v) {if(op == 1) eedge[eedge_cnt++] = Eedge(1,u,v);}
else {if(op == 1) eedge[eedge_cnt++] = Eedge(1,v,u);}
}
sort(eedge,eedge+eedge_cnt);
FOR(i,0,N) G[i].clear();
int it_cnt = 1;
FOR(i,1,eedge_cnt){
if(eedge[i].u != eedge[i-1].u || eedge[i].v != eedge[i-1].v){
if(it_cnt){
G[eedge[i-1].u].push_back(eedge[i-1].v);
G[eedge[i-1].v].push_back(eedge[i-1].u);
st[make_pair(eedge[i-1].u,eedge[i-1].v)] = it_cnt;
st[make_pair(eedge[i-1].v,eedge[i-1].u)] = it_cnt;
}
it_cnt = 1;
continue;
}
if(!eedge[i].type) it_cnt ++;
else it_cnt --;
}
if(it_cnt){
G[eedge[eedge_cnt-1].u].push_back(eedge[eedge_cnt-1].v);
G[eedge[eedge_cnt-1].v].push_back(eedge[eedge_cnt-1].u);
st[make_pair(eedge[eedge_cnt-1].u,eedge[eedge_cnt-1].v)] = it_cnt;
st[make_pair(eedge[eedge_cnt-1].v,eedge[eedge_cnt-1].u)] = it_cnt;
}
}
int ans[Q];
int val[N],val0[N];
int edge_cnt,head[N];
struct Edge{
int u,v,sz_cnt;
int nt;
}edge[N<<1];
void add_edge(int u,int v,int sz_cnt){
edge[edge_cnt].v = v;
edge[edge_cnt].sz_cnt = sz_cnt;
edge[edge_cnt].nt = head[u];
head[u] = edge_cnt ++;
}
void Build_Graph(){
edge_cnt = 0;
FOR(u,1,n+1){
for(int i = 0;i < G[u].size();i ++){
int v = G[u][i];
if(pos[u] != pos[v]){
add_edge(pos[u],pos[v],st[make_pair(u,v)]);
}
}
}
}
int top[N],sz[N],fa[N],w[N],son[N],dep[N];
int totw;
bool vis[N];
void dfs1(int u,int father,int depth){
sz[u] = 1; fa[u] = father; dep[u] = depth; vis[u] = true;
int idd = -1,maxx = -1;
for(int i = head[u];i != -1;i = edge[i].nt){
int v = edge[i].v;
if(vis[v]) continue;
if(v == father) continue;
val0[v] = edge[i].sz_cnt;
dfs1(v,u,depth+1);
sz[u] += sz[v];
if(sz[v] > maxx){
maxx = sz[v]; idd = v;
}
}
son[u] = idd;
}
void dfs2(int u,int father){
vis[u] = true;
if(son[u] == -1) return;
top[son[u]] = top[u];
w[son[u]] = ++totw;
val[totw] = val0[son[u]];
dfs2(son[u],u);
for(int i = head[u];i != -1;i = edge[i].nt){
int v = edge[i].v;
if(vis[v]) continue;
if(v == father) continue;
if(v == son[u]) continue;
top[v] = v;
w[v] = ++totw;
val[totw] = val0[v];
dfs2(v,u);
}
}
struct Tree{
int l,r;
int lazy,sum;
}tree[N<<2];
void Update_Lazy(int rt){
tree[rt].sum = 0;
tree[rt].lazy = 0;
}
void PushDown(int rt){
if(!tree[rt].lazy){
Update_Lazy(lrt);
Update_Lazy(rrt);
tree[rt].lazy = 1;
}
}
void PushUp(int rt){
tree[rt].sum = tree[lrt].sum + tree[rrt].sum;
}
void Build(int rt,int l,int r){
tree[rt].l = l; tree[rt].r = r;
tree[rt].lazy = 1;
if(l == r){
if(val[l] == 1) tree[rt].sum = 1;
else tree[rt].sum = 0;
return ;
}
int mid = (l+r) >> 1;
Build(lson);
Build(rson);
PushUp(rt);
}
int Query(int rt,int l,int r){
if(tree[rt].l == l && tree[rt].r == r) return tree[rt].sum;
PushDown(rt);
int mid = (tree[rt].l + tree[rt].r) >> 1;
if(r <= mid) return Query(lrt,l,r);
else if(l > mid) return Query(rrt,l,r);
else {
return Query(lson)+Query(rson);
}
}
void Modify(int rt,int l,int r){
if(tree[rt].l == l && tree[rt].r == r){
Update_Lazy(rt);
return;
}
PushDown(rt);
int mid = (tree[rt].l + tree[rt].r) >> 1;
if(r <= mid) Modify(lrt,l,r);
else if(l > mid) Modify(rrt,l,r);
else{
Modify(lson);
Modify(rson);
}
PushUp(rt);
}
int C_Query(int l,int r){
int res = 0;
while(top[l] != top[r]){
if(dep[top[l]] >= dep[top[r]]){
res += Query(1,w[top[l]],w[l]);
l = fa[top[l]];
}
else{
res += Query(1,w[top[r]],w[r]);
r = fa[top[r]];
}
}
if(l == r) return res;
if(dep[l] >= dep[r]){
res += Query(1,w[r]+1,w[l]);
}
else
res += Query(1,w[l]+1,w[r]);
return res;
}
void C_Modify(int l,int r){
while(top[l] != top[r]){
if(dep[top[l]] >= dep[top[r]]){
Modify(1,w[top[l]],w[l]);
l = fa[top[l]];
}
else{
Modify(1,w[top[r]],w[r]);
r = fa[top[r]];
}
}
if(l == r) return;
if(dep[l] >= dep[r]){
Modify(1,w[r]+1,w[l]);
}
else
Modify(1,w[l]+1,w[r]);
}
int main()
{
//freopen("test.in","r",stdin);
int T,tCase = 0;
scanf("%d",&T);
while(T--){
printf("Case #%d:\n",++tCase);
scanf("%d%d%d",&n,&m,&q);
init();
dfs_clock = 0;
memset(dfn,0,sizeof(dfn));
dfs(1,-1);
memset(head,-1,sizeof(head));
Build_Graph();
memset(vis,false,sizeof(vis));
dfs1(1,-1,1);
totw = 0;
top[1] = 1;
memset(vis,false,sizeof(vis));
dfs2(1,-1);
Build(1,1,totw);
IFOR(i,q-1,-1){
if(cmd[i].op == 1){
if(pos[cmd[i].u] == pos[cmd[i].v]) continue;
C_Modify(pos[cmd[i].u],pos[cmd[i].v]);
}
else{
if(pos[cmd[i].u] == pos[cmd[i].v]) ans[i] = 0;
else{
ans[i] = C_Query(pos[cmd[i].u],pos[cmd[i].v]);
}
}
}
FOR(i,0,q){
if(cmd[i].op == 2) printf("%d\n",ans[i]);
}
}
return 0;
}