首先同一个点双内部的加边肯定不影响。。所以先缩点成树,然后每次加一条边,这条对应的树上路径上所有边就都不是桥了,且每次操作独立作用,不相互影响(不过有可能本来一条边已经不是桥了又被标记了一次),所以每次相当对树链做一次链覆盖,统计未覆盖边。这个是链剖板子。。$O(N\log^2N)$

1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 #include<cmath>
6 #include<queue>
7 #define mst(x) memset(x,0,sizeof x)
8 #define dbg(x) cerr << #x << " = " << x <<endl
9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
10 using namespace std;
11 typedef long long ll;
12 typedef double db;
13 typedef pair<int,int> pii;
14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
19 template<typename T>inline T read(T&x){
20 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
21 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
22 }
23 const int N=1e5+7;
24 int n,m,q,cas,fir;
25 struct thxorz{
26 int head[N],nxt[N<<2],to[N<<2],tot;
27 inline void add(int x,int y){
28 to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
29 to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
30 }
31 #define y to[j]
32 int dfn[N],low[N],cut[N<<2],bel[N],tim,dcc;
33 void tarjan(int x,int las){
34 dfn[x]=low[x]=++tim;
35 for(register int j=head[x];j;j=nxt[j])if(j^(las^1)){
36 if(!dfn[y]){
37 tarjan(y,j),MIN(low[x],low[y]);
38 if(low[y]>dfn[x])cut[j]=cut[j^1]=1;
39 }
40 else MIN(low[x],dfn[y]);
41 }
42 }
43 void dfs(int x){
44 bel[x]=dcc;//dbg2(x,dcc);
45 for(register int j=head[x];j;j=nxt[j])if(!cut[j]&&!bel[y])dfs(y);
46 }
47 #undef y
48 inline void clear(){mst(head),mst(dfn),mst(cut),mst(bel),tim=dcc=0,tot=1;}
49 }G;
50 struct uuzlovetree{
51 int head[N],nxt[N<<1],to[N<<1],tot;
52 inline void add(int x,int y){
53 to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
54 to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
55 }
56 #define y to[j]
57 int fa[N],topfa[N],cnt[N],son[N],pos[N],dep[N],tim;
58 void dfs1(int x,int fat){//dbg(x);
59 fa[x]=fat,cnt[x]=1,dep[x]=dep[fat]+1;int tmp=-1;
60 for(register int j=head[x];j;j=nxt[j])if(y^fat)dfs1(y,x),cnt[x]+=cnt[y],MAX(tmp,cnt[y])&&(son[x]=y);
61 }
62 void dfs2(int x,int topf){
63 topfa[x]=topf,pos[x]=++tim;if(!son[x])return;dfs2(son[x],topf);
64 for(register int j=head[x];j;j=nxt[j])if(y^fa[x]&&y^son[x])dfs2(y,y);
65 }
66 #undef y
67 int tag[N<<2],sumv[N<<2];
68 #define lc i<<1
69 #define rc i<<1|1
70 inline void pushup(int i){sumv[i]=sumv[lc]+sumv[rc];}
71 inline void pushdown(int i){
72 if(tag[i])tag[lc]=tag[rc]=1,sumv[lc]=sumv[rc]=0,tag[i]=0;
73 }
74 void Build(int i,int L,int R){//dbg(i),dbg2(L,R);
75 if(L==R){sumv[i]=1;tag[i]=0;return;}
76 int mid=L+R>>1;
77 Build(lc,L,mid),Build(rc,mid+1,R);pushup(i);
78 }
79 void Update(int i,int L,int R,int ql,int qr){
80 if(ql<=L&&qr>=R){tag[i]=1,sumv[i]=0;return;}
81 int mid=L+R>>1;
82 pushdown(i);
83 if(ql<=mid)Update(lc,L,mid,ql,qr);
84 if(qr>mid)Update(rc,mid+1,R,ql,qr);
85 pushup(i);
86 }
87 #undef lc
88 #undef rc
89 inline void tree_update(int x,int y){
90 while(topfa[x]^topfa[y]){
91 if(dep[topfa[x]]<dep[topfa[y]])_swap(x,y);
92 Update(1,2,tim,pos[topfa[x]],pos[x]),x=fa[topfa[x]];
93 }
94 if(dep[y]<dep[x])_swap(x,y);
95 if(x^y)Update(1,2,tim,pos[x]+1,pos[y]);
96 }
97 inline void clear(){mst(head),mst(tag),mst(sumv),mst(son),tim=tot=0;}
98 }T;
99
100 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
101 while(read(n),read(m),n||m){
102 G.clear(),T.clear();
103 for(register int i=1,x,y;i<=m;++i)read(x),read(y),G.add(x,y);
104 for(register int i=1;i<=n;++i)if(!G.dfn[i])G.tarjan(i,0);
105 for(register int i=1;i<=n;++i)if(!G.bel[i])++G.dcc,G.dfs(i);
106 for(register int t=2;t<=G.tot;t+=2){
107 int x=G.to[t],y=G.to[t^1];
108 if(G.bel[x]^G.bel[y])T.add(G.bel[x],G.bel[y]);//dbg2(G.bel[x],G.bel[y]);
109 }
110 T.dfs1(1,0);T.dfs2(1,1);
111 T.Build(1,2,T.tim);
112 read(q);if(fir)puts("");fir=1;
113 printf("Case %d:\n",++cas);
114 for(register int i=1,x,y;i<=q;++i){
115 read(x),read(y);T.tree_update(G.bel[x],G.bel[y]);
116 printf("%d\n",T.sumv[1]);
117 }
118 }
119 return 0;
120 }
发现自己数据结构学傻掉了。。完全不需要的说。。因为每次加边的时候这个链就是一个环了对不对。。然后实际上可以看成再缩成一个大点,然后每次询问只要暴力往上爬到lca就好了。。具体实现的话呢,使用并查集来合并的,爬过的所有点(不管是原点还是后来的缩的点)都合并起来,所谓的看成大点就是把所有点所在的这个集合的根设为这个块最顶端的点,这样既方便合并,也方便跳,每次虽然是暴力跳的,但是每跳一次就会合并一次,合并$n$次,需要跳的越来越少,所以爬是线性的。。。但是被两个$\log$的链剖吊打了?

1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 #include<cmath>
6 #include<queue>
7 #define mst(x) memset(x,0,sizeof x)
8 #define dbg(x) cerr << #x << " = " << x <<endl
9 #define dbg2(x,y) cerr<< #x <<" = "<< x <<" "<< #y <<" = "<< y <<endl
10 using namespace std;
11 typedef long long ll;
12 typedef double db;
13 typedef pair<int,int> pii;
14 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
15 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
16 template<typename T>inline char MIN(T&A,T B){return A>B?(A=B,1):0;}
17 template<typename T>inline char MAX(T&A,T B){return A<B?(A=B,1):0;}
18 template<typename T>inline void _swap(T&A,T&B){A^=B^=A^=B;}
19 template<typename T>inline T read(T&x){
20 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
21 while(isdigit(c))x=x*10+(c&15),c=getchar();return f?x=-x:x;
22 }
23 const int N=1e5+7;
24 int n,m,q,cas,fir,ans;
25 struct thxorz{
26 int head[N],nxt[N<<2],to[N<<2],tot;
27 inline void add(int x,int y){
28 to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
29 to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
30 }
31 #define y to[j]
32 int dfn[N],low[N],cut[N<<2],bel[N],tim,dcc;
33 void tarjan(int x,int las){
34 dfn[x]=low[x]=++tim;
35 for(register int j=head[x];j;j=nxt[j])if(j^(las^1)){
36 if(!dfn[y]){
37 tarjan(y,j),MIN(low[x],low[y]);
38 if(low[y]>dfn[x])cut[j]=cut[j^1]=1;
39 }
40 else MIN(low[x],dfn[y]);
41 }
42 }
43 void dfs(int x){
44 bel[x]=dcc;//dbg2(x,dcc);
45 for(register int j=head[x];j;j=nxt[j])if(!cut[j]&&!bel[y])dfs(y);
46 }
47 #undef y
48 inline void clear(){mst(head),mst(dfn),mst(cut),mst(bel),tim=dcc=0,tot=1;}
49 }G;
50 struct uuzlovetree{
51 int head[N],nxt[N<<1],to[N<<1],tot;
52 inline void add(int x,int y){
53 to[++tot]=y,nxt[tot]=head[x],head[x]=tot;
54 to[++tot]=x,nxt[tot]=head[y],head[y]=tot;
55 }
56 #define y to[j]
57 int fa[N],dep[N],n;
58 void dfs1(int x,int fat){//dbg(x);
59 fa[x]=fat,dep[x]=dep[fat]+1;
60 for(register int j=head[x];j;j=nxt[j])if(y^fat)dfs1(y,x);
61 }
62 #undef y
63 int anc[N];
64 int Find(int x){return anc[x]==x?x:anc[x]=Find(anc[x]);}
65 inline void stostostostothxorzorzorzorz(int x,int y){
66 x=Find(x),y=Find(y);
67 while(x^y){
68 if(dep[x]<dep[y])_swap(x,y);
69 int tmp=Find(fa[x]);
70 anc[x]=tmp,x=tmp;
71 --ans;
72 }
73 }
74 inline void clear(){mst(head),tot=n=0;}
75 }T;
76
77 int main(){//freopen("test.in","r",stdin);//freopen("test.ans","w",stdout);
78 while(read(n),read(m),n||m){
79 G.clear(),T.clear();
80 for(register int i=1,x,y;i<=m;++i)read(x),read(y),G.add(x,y);
81 for(register int i=1;i<=n;++i)if(!G.dfn[i])G.tarjan(i,0);
82 for(register int i=1;i<=n;++i)if(!G.bel[i])++G.dcc,G.dfs(i);
83 for(register int t=2;t<=G.tot;t+=2){
84 int x=G.to[t],y=G.to[t^1];
85 if(G.bel[x]^G.bel[y])T.add(G.bel[x],G.bel[y]);//dbg2(G.bel[x],G.bel[y]);
86 }
87 T.dfs1(1,0);ans=G.dcc-1;
88 for(register int i=1;i<=G.dcc;++i)T.anc[i]=i;
89 read(q);if(fir)puts("");fir=1;
90 printf("Case %d:\n",++cas);
91 for(register int i=1,x,y;i<=q;++i){
92 read(x),read(y);
93 T.stostostostothxorzorzorzorz(G.bel[x],G.bel[y]);
94 printf("%d\n",ans);
95 }
96 }
97 return 0;
98 }
