q次询问 每一次加一条边 问加完这条边之后还剩多少割边
可以想到 对于一个无向图 缩完点之后就是一棵树 且树上的边就是原图中的割边
对于每一次加边操作 如果两点不在一个连通分量之中 就会把两点之间的所有割边全部去掉 形成有一个新的连通分量 相当于修改新树图中的一条链 这个过程用树链剖分维护一下就好了
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct node1 { int v; int next; int flag; }; struct node2 { int l; int r; int laz; int val; }; node1 edge1[400010],edge2[400010]; node2 tree[400010]; int first1[100010],first2[100010],dfn[100010],low[100010],belong[100010],degree[100010]; int pre[100010],fa[100010],deep[100010],sum[100010],son[100010],top[100010],mp1[100010],mp2[100010],mp3[100010]; int n,m,num,cnt,ans; void addedge(node1* edge,int* first,int u,int v) { edge[num].v=v; edge[num].next=first[u]; edge[num].flag=0; first[u]=num++; return; } void dfsI(int cur,int pre) { int tmp,i,v; num++; dfn[cur]=num,low[cur]=num; tmp=0; for(i=first1[cur];i!=-1;i=edge1[i].next) { v=edge1[i].v; if(dfn[v]==0) { dfsI(v,cur); low[cur]=min(low[cur],low[v]); if(low[v]>dfn[cur]) { edge1[i].flag=1; edge1[i^1].flag=1; } } else if(v==pre) { if(tmp>0) low[cur]=min(low[cur],dfn[v]); tmp++; } else { low[cur]=min(low[cur],dfn[v]); } } return; } void dfsII(int cur) { int i,v; for(i=first1[cur];i!=-1;i=edge1[i].next) { v=edge1[i].v; if(!belong[v]&&!edge1[i].flag) { belong[v]=cnt; dfsII(v); } } return; } void tarjan() { int i,u,v; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); num=0,ans=0; for(u=1;u<=n;u++) { if(!dfn[u]) { dfsI(u,-1); } } memset(belong,0,sizeof(belong)); cnt=0; for(u=1;u<=n;u++) { if(!belong[u]) { cnt++; belong[u]=cnt; dfsII(u); } } /* printf("***%d***\n",cnt); for(i=1;i<=n;i++) { printf("%d ",belong[i]); } printf("\n"); */ ans=cnt-1; memset(first2,-1,sizeof(first2)); num=0; for(u=1;u<=n;u++) { for(i=first1[u];i!=-1;i=edge1[i].next) { v=edge1[i].v; if(belong[u]!=belong[v]) { addedge(edge2,first2,belong[u],belong[v]); } } } return; } void dfsIII(int cur) { int i,v,w; sum[cur]=1,son[cur]=-1; for(i=first2[cur];i!=-1;i=edge2[i].next) { v=edge2[i].v; if(v!=fa[cur]) { pre[v]=1,fa[v]=cur,deep[v]=deep[cur]+1; mp3[i/2+1]=v; dfsIII(v); sum[cur]+=sum[v]; if(son[cur]==-1||sum[son[cur]]<sum[v]) { son[cur]=v; } } } return; } void dfsIV(int cur,int tp) { int i,v; num++; top[cur]=tp,mp1[cur]=num,mp2[num]=cur; if(son[cur]==-1) return; dfsIV(son[cur],tp); for(i=first2[cur];i!=-1;i=edge2[i].next) { v=edge2[i].v; if(v!=fa[cur]&&v!=son[cur]) { dfsIV(v,v); } } return; } void pushup(int cur) { tree[cur].val=tree[2*cur].val+tree[2*cur+1].val; return; } void pushdown(int cur) { if(tree[cur].laz) { tree[2*cur].val=0; tree[2*cur].laz=1; tree[2*cur+1].val=0; tree[2*cur+1].laz=1; tree[cur].laz=0; } return; } void build(int l,int r,int cur) { int m; tree[cur].l=l; tree[cur].r=r; tree[cur].laz=0; if(l==r) { tree[cur].val=1; return; } m=(l+r)/2; build(l,m,2*cur); build(m+1,r,2*cur+1); pushup(cur); return; } int query(int pl,int pr,int cur) { int res; if(pl<=tree[cur].l&&tree[cur].r<=pr) { return tree[cur].val; } pushdown(cur); res=0; if(pl<=tree[2*cur].r) res+=query(pl,pr,2*cur); if(pr>=tree[2*cur+1].l) res+=query(pl,pr,2*cur+1); return res; } void update(int pl,int pr,int cur) { if(pl<=tree[cur].l&&tree[cur].r<=pr) { tree[cur].val=0; tree[cur].laz=1; return; } pushdown(cur); if(pl<=tree[2*cur].r) update(pl,pr,2*cur); if(pr>=tree[2*cur+1].l) update(pl,pr,2*cur+1); pushup(cur); return; } int ask(int u,int v) { int res; res=0; while(top[u]!=top[v]) { if(deep[top[u]]<deep[top[v]]) swap(u,v); res+=query(mp1[top[u]],mp1[u],1); u=fa[top[u]]; } if(u==v) return res; if(deep[u]<deep[v]) swap(u,v); res+=query(mp1[son[v]],mp1[u],1); return res; } void change(int u,int v) { while(top[u]!=top[v]) { if(deep[top[u]]<deep[top[v]]) swap(u,v); update(mp1[top[u]],mp1[u],1); u=fa[top[u]]; } if(deep[u]<deep[v]) swap(u,v); update(mp1[v],mp1[u],1); return; } void solve() { pre[1]=0,fa[1]=0,deep[1]=1; dfsIII(1); num=0; dfsIV(1,1); build(1,cnt,1); return; } int main() { int cas,q,i,u,v; cas=1; while(scanf("%d%d",&n,&m)!=EOF) { if(n==0&&m==0) break; memset(first1,-1,sizeof(first1)); num=0; for(i=1;i<=m;i++) { scanf("%d%d",&u,&v); addedge(edge1,first1,u,v); addedge(edge1,first1,v,u); } tarjan(); solve(); printf("Case %d:\n",cas++); scanf("%d",&q); while(q--) { scanf("%d%d",&u,&v); if(belong[u]!=belong[v]) { ans-=ask(belong[u],belong[v]); change(belong[u],belong[v]); } printf("%d\n",ans); } printf("\n"); } return 0; }