[cf1616G]Just Add an Edge
记边集为$E$,新建点$0$向$[1,n]$连边$,n+1$从$[1,n]$连边,以此确定起点和终点
若初始$\forall 0\le i\le n,(i,i+1)\in E$,显然答案即${n\choose 2}$,不妨特判此类情况
此时考虑加入$(x,y)$后能否合法,不难证明路径必然为以下形式
$$
0\rightarrow (y-1)\rightsquigarrow x\rightarrow y\rightsquigarrow (x+1)\rightarrow (n+1)
$$
说明:
1.$x\rightarrow y$使用新建的边$(x,y)$
2.$0\rightarrow (y-1)$和$(x+1)\rightarrow (n+1)$要求$\forall i\in [0,y-2]\cup [x+1,n],(i,i+1)\in E$
3.$(y-1)\rightsquigarrow x$和$y\rightsquigarrow (x+1)$要求经过的点无交且并为$[y-1,x+1]$
根据初始特判的条件,任选$0\le z\le n$使得$(z,z+1)\not\in E$(必然存在)
若第2个条件成立,则$z\not\in [0,y-2]\cup [x+1,n]$,进而即有$y-1\le z\le x$
不难证明,(第3点中)两条链不断向前拓展,总会经过状态$(z,z+1)$或$(z+1,z)$
换言之,从这两个状态出发,向两侧分别去搜索所有形如$(k,k\pm 1)$的状态即可
时间复杂度为$o(n+m)$,可以通过
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 150005 4 #define ll long long 5 vector<int>v[N],rev_v[N]; 6 int t,n,m,x,y,fa[N],X[4],Y[4],vis[N][2]; 7 ll ans; 8 int find(int k){ 9 if (k==fa[k])return k; 10 return fa[k]=find(fa[k]); 11 } 12 void merge(int x,int y){ 13 x=find(x),y=find(y); 14 if (x!=y)fa[x]=y; 15 } 16 void add(int x,int y){ 17 if (y==x+1)merge(x,y); 18 v[x].push_back(y); 19 rev_v[y].push_back(x); 20 } 21 void dfs1(int k,int p,int P){ 22 if (vis[k][p+1>>1]&P)return; 23 vis[k][p+1>>1]|=P; 24 if (p>0){ 25 for(int i=0;i<v[k].size();i++) 26 if ((v[k][i]>k+1)&&(fa[k+1]==fa[v[k][i]-1]))dfs1(v[k][i],-1,P); 27 } 28 else{ 29 for(int i=0;i<v[k-1].size();i++) 30 if ((v[k-1][i]>k)&&(fa[k]==fa[v[k-1][i]-1]))dfs1(v[k-1][i]-1,1,P); 31 } 32 } 33 void dfs2(int k,int p,int P){ 34 if (vis[k][p+1>>1]&P)return; 35 vis[k][p+1>>1]|=P; 36 if (p>0){ 37 for(int i=0;i<rev_v[k+1].size();i++) 38 if ((rev_v[k+1][i]<k)&&(fa[k]==fa[rev_v[k+1][i]+1]))dfs2(rev_v[k+1][i]+1,-1,P); 39 } 40 else{ 41 for(int i=0;i<rev_v[k].size();i++) 42 if ((rev_v[k][i]<k-1)&&(fa[k-1]==fa[rev_v[k][i]+1]))dfs2(rev_v[k][i],1,P); 43 } 44 } 45 int main(){ 46 scanf("%d",&t); 47 while (t--){ 48 scanf("%d%d",&n,&m); 49 for(int i=0;i<=n+1;i++){ 50 fa[i]=i; 51 v[i].clear(),rev_v[i].clear(); 52 } 53 for(int i=1;i<=n;i++)add(0,i),add(i,n+1); 54 for(int i=1;i<=m;i++){ 55 scanf("%d%d",&x,&y); 56 add(x,y); 57 } 58 for(int i=0;i<=n+1;i++)fa[i]=find(i); 59 if (fa[0]>n){ 60 printf("%lld\n",(ll)n*(n-1)/2); 61 continue; 62 } 63 memset(vis,0,sizeof(vis)); 64 dfs1(fa[0],1,1),vis[fa[0]][1]=0,dfs2(fa[0],1,1); 65 dfs1(fa[0]+1,-1,2),vis[fa[0]+1][0]=0,dfs2(fa[0]+1,-1,2); 66 for(int p=1;p<4;p++)X[p]=Y[p]=0; 67 for(int i=1;i<=fa[0]+1;i++) 68 for(int p=1;p<4;p++) 69 if ((p&vis[i-1][1])==p)X[p]++; 70 for(int i=fa[0];i<=n;i++) 71 if (fa[i+1]>n){ 72 for(int p=1;p<4;p++) 73 if ((p&vis[i][1])==p)Y[p]++; 74 } 75 ans=(ll)X[1]*Y[1]+(ll)X[2]*Y[2]-(ll)X[3]*Y[3]; 76 if (fa[fa[0]+1]>n)ans--; 77 printf("%lld\n",ans); 78 } 79 return 0; 80 }