分析
考虑求出边双连通分量,那么题目其实就是在问,有多少个桥。那么由于边双缩点之后,整个图变为树。那么树的边数就是答案。考虑新加一条边之后的贡献。那么就是树上距离,在将这个链上的权值变为 。这个考虑树链剖分或者
维护,写完才发现,好像直接并查集时间复杂度好像还要更优。这里采用了
实现,时间总复杂度为
。
代码
#include<bits/stdc++.h>
using namespace std;
int read() {
int x = 0,f = 0;char ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = 1;ch = getchar();}
while(isdigit(ch)) {x = x * 10 + ch - '0';ch = getchar();}
return f ? -x : x;
}
const int N = 4e5 + 1000;
struct Lct {
bool r[N];
int val[N],sum[N],ch[N][2],tag[N],fa[N];
void pushr(int x) {swap(ch[x][1],ch[x][0]);r[x] ^= 1;}
bool nroot(int x) {return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
void pushup(int x) {sum[x] = (val[x] + sum[ch[x][0]] + sum[ch[x][1]]);}
void pusha(int x) {sum[x] = val[x] = 0;tag[x] = 1;}
void pushdown(int x) {
if(r[x]) {if(ch[x][0]) pushr(ch[x][0]);if(ch[x][1]) pushr(ch[x][1]);r[x] = 0;}
if(tag[x]) {if(ch[x][0]) pusha(ch[x][0]);if(ch[x][1]) pusha(ch[x][1]);tag[x] = 0;}
}
void push(int x) {if(nroot(x))push(fa[x]);pushdown(x);}
void rotate(int x) {
int y = fa[x],z = fa[y],k = (ch[y][1] == x),w = ch[x][!k];
if(nroot(y)) ch[z][ch[z][1] == y] = x;ch[y][k] = w;ch[x][!k] = y;
if(w) fa[w] = y;fa[x] = z;fa[y] = x;pushup(y);
}
void splay(int x) {
push(x);while(nroot(x)) {
int y = fa[x],z = fa[y];
if(nroot(y)) rotate(((ch[z][1]==y)^(ch[y][1]==x))?y:x);
rotate(x);pushup(x);
}
}
void access(int x) {for(int y = 0;x;x = fa[y=x])splay(x),ch[x][1]=y,pushup(x);}
void makeroot(int x) {access(x);splay(x);pushr(x);}
void split(int x,int y) {makeroot(x);access(y);splay(y);}
void link(int x,int y) {split(x,y);fa[x] = y;}
int ask(int x,int y) {split(x,y);int ans = sum[y];pusha(y);return ans;}
void clear(int tot) {for(int x=0;x<=tot;x++)ch[x][1]=ch[x][0]=tag[x]=val[x]=sum[x]=r[x]=fa[x]=0;}
}t;
int low[N],dfn[N],dcc[N],vis[N],st[N],top,n,m,tot,Dfn,Dcc;
vector<int> G[N],id[N];
void tarjan(int x,int fa) {
low[x] = dfn[x] = ++Dfn;
st[++top] = x;vis[x] = 1;
for(int i = 0 ;i < G[x].size();i++) {
if(id[x][i] == fa) continue;int y = G[x][i];
if(!dfn[y]) tarjan(y,id[x][i]),low[x] = min(low[x],low[y]);
else if(vis[y]) low[x] = min(dfn[y],low[x]);
}
if(low[x] == dfn[x]) {
Dcc++;dcc[x] = Dcc;vis[x] = 0;
while(st[top] != x) {
dcc[st[top]] = Dcc;vis[st[top]] = 0;
top--;
}
top--;
}
}
int main() {
int Case = 0;
while(1) {
n = read();m = read();
if(n == 0 && m == 0) break;printf("Case %d:\n",++Case);
t.clear(tot);tot = 0;Dfn = 0,Dcc = 0;top = 0;
for(int i = 1;i <= n;i++) {
G[i].clear();id[i].clear();
st[i] = vis[i] = low[i] = dfn[i] = dcc[i] = 0;
}
for(int i = 1;i <= m;i++) {
int u = read(),v = read();
G[u].push_back(v);G[v].push_back(u);
id[u].push_back(i);id[v].push_back(i);
}
for(int i = 1;i <= n;i++) if(!dfn[i]) tarjan(i,0);
tot = Dcc;
for(int x = 1;x <= n;x++) {
for(auto y : G[x]) {
if(x > y) continue;
if(dcc[y] == dcc[x]) continue;
++tot;t.val[tot] = 1;
t.link(dcc[y],tot);
t.link(dcc[x],tot);
}
}
int Q = read(),res = 0;
while(Q--) {
int x = read(),y = read();
if(dcc[x] != dcc[y]) res += t.ask(dcc[x],dcc[y]);
printf("%d\n",Dcc - res - 1);
}
printf("\n");
}
}
京公网安备 11010502036488号