思路
一看到这题我就想起了gmoj3883。
本质上这道题也可以用染色的思想做,先随便建一棵树,然后每条非树边都可以看成一次染色,然后新染色的数量就是答案减少的数量。
当然,如果一开始不是联通的就不行了(但其它方法也不行)。
跑一下tarjan求LCA再用并查集缩点即可。
但我没有写(一般意义上的)并查集,而是用了一种玄学的方法来做。
具体见gmoj3883题解。
代码
#include<cstdio>
#include<cstring>
#define N 500010
#define now st[size]
using namespace std;
int n,m,ans,q,s[N],last,a[N],b[N][2],ques[N][3],lca[N],up[N],dp[N],st[N],si[N];
int qlast,qa[N],qb[N][3],least[N][2];
bool nbi[N];
template<typename T>void read(T &x){
char c=getchar();
for(;c<33;c=getchar());
for(x=0;(47<c)&&(c<58);x=x*10+c-48,c=getchar());
}
void add(int x,int y){
b[++last][0]=a[x];
b[last][1]=y;
a[x]=last;
}
void qadd(int x,int y,int z){
qb[++qlast][0]=qa[x];
qb[qlast][1]=y;
qb[qlast][2]=z;
qa[x]=qlast;
}
int root(int m){
return(s[m]?s[m]=root(s[m]):m);
}
void tarjan(){
int size=1;
st[1]=1;
while(size){
if(si[now]){
s[root(b[si[now]][1])]=root(now);
si[now]=b[si[now]][0];
}else{
si[now]=a[now];
}
for(;b[si[now]][1]==up[now]&&si[now];si[now]=b[si[now]][0]);
if(si[now]){
dp[b[si[now]][1]]=dp[now]+1;
st[size+1]=b[si[now]][1];
up[b[si[now]][1]]=now;
size++;
}else{
for(int i=qa[now];i;i=qb[i][0]){
int get=root(qb[i][1]);
if((get!=qb[i][1])||(get==now)){
lca[qb[i][2]]=get;
}
}
size--;
}
}
}
int sg(int x,int l){
int re=0;
for(int temp;dp[x]>dp[l];x=temp){
temp=up[x];
up[x]=l; //这条语句很有趣,因为这不是并查集,如果放在下面的if内会被卡掉
if(!nbi[x]){
nbi[x]=1;
re++;
}
}
return(re);
}
int main(){
read(n);read(m);
ans=n-1;
for(int i=1;i<=m;i++){
int x,y;
read(x);read(y);
if(root(x)!=root(y)){
add(x,y);
add(y,x);
s[root(x)]=root(y);
}else{
least[++least[0][0]][0]=x;
least[least[0][0]][1]=y;
}
}
memset(s,0,sizeof(s));
for(int i=1;i<=least[0][0];i++){
qadd(least[i][0],least[i][1],i);
qadd(least[i][1],least[i][0],i);
}
read(q);
for(int i=least[0][0]+1;i<=q+least[0][0];i++){
read(ques[i][0]);read(ques[i][1]);
qadd(ques[i][0],ques[i][1],i);
qadd(ques[i][1],ques[i][0],i);
}
tarjan();
for(int i=1;i<=least[0][0];i++){
ans-=sg(least[i][0],lca[i])+sg(least[i][1],lca[i]);
}
for(int i=least[0][0]+1;i<=q+least[0][0];i++){
ans-=sg(ques[i][0],lca[i])+sg(ques[i][1],lca[i]);
printf("%d
",ans);
}
}