Description
有n对夫妇,一开始夫妇之间互不认识,若两男或两女成为朋友,称他们为"熟人","熟人"关系具有传递性,即若a熟b且b熟c则a熟c.若两组夫妇的丈夫互相为熟人且妻子也相互为熟人则称他们为"熟悉的一对",现在给出q个事件,每个事件会使得两男或两女成为朋友,并在每次事件之后计算"熟悉的一对"的个数.
Input
第一行一个数T表示数据组数
接下来n,q表示对数和事件数
接下来q行,每行t,a,b,若t=1,表示男a和男b成为朋友,t=2,表示女a和女b成为朋友
Output
设当前是第i个操作,y_i为本次事件之后的答案,令z_i=i*y_i,请输出z_1+z_2+...+z_q模10^9+7
题意简化为维护两个图,支持在一个图中连边和询问有多少点对在两个图中都连通
用两个并查集分别维护两个图中的连通性,用一个hashmap维护一个n*n的二维数组,f[x][y]表示在并查集1中属于集合x,在并查集2中属于集合y的点的个数
每次在一个图中连边时,若两侧连通则忽略,不联通则遍历小的一个联通块,通过计算在另一个图中跨过两个联通块的联通块更新答案
均摊时间复杂度O(Tnlogn)
#include<cstdio>#include<vector> const int P=1e9+7,N=1e6+5; inline int read(){ int x=0,c=getchar(); while(c>'9'||c<'0')c=getchar(); while(c>='0'&&c<='9')x=x*10+c-'0',c=getchar(); return x; } inline void exch(int&a,int&b){int c=a;a=b;b=c;}namespace Map{ const int mx=2939999; unsigned int nw=0; unsigned int xs[mx],ys[mx],zs[mx],ds[mx]; inline void clear(){ nw++; } inline int get(unsigned int x,unsigned int y,int inc){ unsigned int w=(x*17+y*53+3)%mx; while(ds[w]==nw){ if(xs[w]==x&&ys[w]==y){ int v=zs[w]; zs[w]+=inc; return v; } w+=1237; if(w>=mx)w-=mx; } ds[w]=nw; xs[w]=x;ys[w]=y;zs[w]=inc; return 0; } } int T,n,m,now=1,Ans,ans; int h1[N],h2[N],f1[N],f2[N],sz1[N],sz2[N],nx1[N],nx2[N]; int t[N],d[N]; std::vector<int>v1[N],v2[N]; int main(){ T=read(); while(T--){ n=read();m=read(); Ans=ans=0; Map::clear(); for(int i=1;i<=n;i++){ Map::get(i,i,1); f1[i]=f2[i]=i; v1[i].clear();v2[i].clear(); v1[i].push_back(i); v2[i].push_back(i); } for(int i=1,op,a,b;i<=m;++i){ op=read();a=read();b=read(); ++now; if(op==1){ if(f1[a]!=f1[b]){ if(v1[f1[a]].size()>v1[f1[b]].size())exch(a,b); std::vector<int>&vc=v1[f1[a]]; for(int x=0;x<vc.size();x++){ int p=vc[x]; int f=f2[p]; if(d[f]!=now)d[f]=now,ans=(ans+Map::get(f1[p],f,-1)*1ll*Map::get(f1[b],f,1)%P)%P; else Map::get(f1[p],f,-1),Map::get(f1[b],f,1); f1[p]=f1[b]; v1[f1[b]].push_back(p); } vc.clear(); } }else{ if(f2[a]!=f2[b]){ if(v2[f2[a]].size()>v2[f2[b]].size())exch(a,b); std::vector<int>&vc=v2[f2[a]]; for(int x=0;x<vc.size();x++){ int p=vc[x]; int f=f1[p]; if(d[f]!=now)d[f]=now,ans=(ans+Map::get(f,f2[p],-1)*1ll*Map::get(f,f2[b],1)%P)%P; else Map::get(f,f2[p],-1),Map::get(f,f2[b],1); f2[p]=f2[b]; v2[f2[b]].push_back(p); } vc.clear(); } } Ans=(Ans+ans*1ll*i%P)%P; } printf("%d\n",Ans); } return 0; }