这一题,我当年只会$60$分做法。。。。。
我们考虑对原图跑一波边双,然后缩成一个森林。
对于森林中的每一棵树,我们钦定一个根。
令$siz[x]$表示以$x$为根的子树中,在原图中点的个数。
令当前的答案为$ans$
对于一条边$(u,v)$,如果这两个点在缩点后的同个点内,那么什么都不用管,直接输出$ans$即可。
否则我们先令$u=d[u]$,$v=d[v]$,其中$d[i]$表示原图中第$i$号点在缩点后的森林中的编号。
显然这两个点在同一棵树内,不妨设$dep[u]>dep[v]$,令$rt$表示$u$所在的树的根。
显然断掉这条边,增加的非联通点对个数为$siz[u]\times (siz[rt]-siz[u])$。
加上$ans$输出即可。
注意对1000取模!!!
#include<bits/stdc++.h>
#define L long long
#define M 100005
using namespace std; struct edge{int u,next;}e[M*]={}; int head[M]={},head1[M]={},use=;
void add(int x,int y){e[use].u=y;e[use].next=head[x];head[x]=use++;}
void add1(int x,int y){use++;e[use].u=y;e[use].next=head1[x];head1[x]=use;}
int dfn[M]={},low[M]={},b[M]={},d[M]={},siz[M]={},cnt=,t=; stack<int> s;
int n,m,q;
void dfs(int x,int fa){
dfn[x]=low[x]=++t; s.push(x); b[x]=;
for(int i=head[x];~i;i=e[i].next)
if(i!=fa){
if(!dfn[e[i].u]) dfs(e[i].u,i^),low[x]=min(low[x],low[e[i].u]);
else if(b[e[i].u]) low[x]=min(low[x],dfn[e[i].u]);
}
if(dfn[x]==low[x]){
cnt++; int u;
do{
u=s.top();s.pop();
b[x]=; d[u]=cnt; siz[cnt]++;
}while(u!=x);
}
}
int du[M]={},dep[M]={},ff[M]={};
void dfs1(int x,int fa){
dep[x]=dep[fa]+; ff[x]=ff[fa];
for(int i=head1[x];i;i=e[i].next)
if(e[i].u!=fa)
dfs1(e[i].u,x),siz[x]+=siz[e[i].u];
} int U[M*]={},V[M*]={};
int main(){
memset(head,-,sizeof(head));
scanf("%d%d%d",&n,&m,&q);
for(int i=;i<=m;i++){
int x,y; scanf("%d%d",&x,&y);
x++; y++;
add(x,y); add(y,x);
U[i]=x; V[i]=y;
}
for(int i=;i<=n;i++) if(!dfn[i])
dfs(i,-);
for(int x=;x<=n;x++)
for(int i=head[x];~i;i=e[i].next)
if(d[x]!=d[e[i].u]){
add1(d[x],d[e[i].u]); du[d[x]]++;
}
L ans=1LL*n*n;
for(int i=;i<=cnt;i++)
if(du[i]==||(du[i]==&&dep[i]==)){
ff[]=i; dfs1(i,);
ans-=1LL*siz[i]*siz[i];
}
ans/=;
while(q--){
int id,x,y; scanf("%d",&id); id++;
x=U[id]; y=V[id];
x=d[x]; y=d[y];
if(x==y||ff[x]!=ff[y]){printf("%lld\n",ans%); continue;}
if(dep[x]<dep[y]) swap(x,y);
L minus=1LL*siz[x]*(siz[ff[y]]-siz[x]);
printf("%lld\n",(ans+minus)%);
}
}