P4630 [APIO2018] 铁人两项(圆方树模版)
*原题链接*
圆方树相关的东西小粉兔讲的太详细了!!(洛谷日报)
在此贴出适合我体质的模版,至于讲解,咱肯定讲的没小粉兔好o(╥﹏╥)o。
(圆方树模版:)
void tarjan(int x){dfn[x]=low[x]=++tim,stk[++top]=x;for(int i=head[x];i;i=edge[i].nxt){int y=edge[i].to;if(!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);if(low[y]==dfn[x]){cnt++;int t;do{t=stk[top--],add(t,cnt),add(cnt,t);}while(t!=y);//注意截止条件add(x,cnt),add(cnt,x);//别忘了和x连边}}else low[x]=min(low[x],dfn[y]);}
}
整题代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=2e5+10;int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();return x*f;
}int n,m,head[N],tot,he[N],tot2,w[N],sz[N],ans,num,vis[N];
int dfn[N],low[N],tim,stk[N],top,cnt;
struct node{int to,nxt;
}e[N*2],edge[N*2];
void add(int x,int y){edge[++tot].to=y;edge[tot].nxt=head[x];head[x]=tot;
}
void ADD(int x,int y){e[++tot2].to=y;e[tot2].nxt=he[x];he[x]=tot2;
}void tarjan(int x){dfn[x]=low[x]=++tim,stk[++top]=x,num++;for(int i=he[x];i;i=e[i].nxt){int y=e[i].to;if(!dfn[y]){tarjan(y);low[x]=min(low[x],low[y]);if(low[y]==dfn[x]){cnt++;int t;do{w[cnt]++,t=stk[top--],add(t,cnt),add(cnt,t);}while(t!=y);add(x,cnt),add(cnt,x),w[cnt]++;}}else low[x]=min(low[x],dfn[y]);}
}void dfs(int x){vis[x]=1;sz[x]=(x<=n);for(int i=head[x];i;i=edge[i].nxt){int y=edge[i].to;if(vis[y]) continue;dfs(y);ans+=2*sz[x]*sz[y]*w[x];sz[x]+=sz[y];}ans+=2*sz[x]*(num-sz[x])*w[x];
}signed main(){n=read(),m=read();cnt=n;for(int i=1;i<=n;i++) w[i]=-1;for(int i=1;i<=m;i++){int x=read(),y=read();ADD(x,y),ADD(y,x);}for(int i=1;i<=n;i++){if(!dfn[i]){memset(vis,0,sizeof(vis)),num=0,tarjan(i),dfs(i);}}cout<<ans<<endl;return 0;
}