圆方树是Tarjan发明,ImmortalCO引入CNOI界的一种处理无向图/仙人掌的利器
具体地,圆方树可以简便地把一个无向图变成树/仙人掌
做法就是Tarjan搜点双的时候,对于每个点双我们建一个方点向这个点双里的点连边,割点向相邻的方点连边
然后就有很多很神仙的性质/应用
但对我来说就是一种优秀的点双缩点写法吧..
代码:APIO2018 铁人两项
#include<bits/stdc++.h> #define LL long long using namespace std; inline int read() { int now = 0,fa = 1;char ch = getchar(); for(;!isdigit(ch);ch = getchar())if(ch == '-') fa = -fa; for(;isdigit(ch);ch = getchar())now = 10 * now + ch - '0'; return now * fa; } const int maxn = 100010; int n,m; struct Graph { int first[maxn],to[maxn << 1],nx[maxn],cnt; inline void add(int u,int v) { to[++cnt] = v; nx[cnt] = first[u]; first[u] = cnt; } }G,Tree; LL val[maxn],ans;int tot; LL sum = 0; int dfn[maxn],low[maxn],stk[maxn],ins[maxn],top,DFN,isc[maxn]; inline void Tarjan(int u,int fa) { sum++; dfn[u] = low[u] = ++DFN;stk[++top] = u;ins[u] = 1; val[u] = -1; for(int i=G.first[u];i;i=G.nx[i]) { int targ = G.to[i]; if(targ == fa)continue; if(!ins[targ]) { Tarjan(targ,u); low[u] = min(low[u],low[targ]); if(low[targ] >= dfn[u]) { tot++; val[tot] = 1; Tree.add(u,tot); do { Tree.add(tot,stk[top]); val[tot]++; }while(targ != stk[top--]); } } else low[u] = min(low[u],dfn[targ]); } } inline int dfs(int x,int type) { LL size = type; for(int i=Tree.first[x];i;i=Tree.nx[i]) { LL now = dfs(Tree.to[i],!type); ans += now * (sum - now) * val[x]; size += now; } ans += (sum - size) * size * val[x]; if(type) ans += (sum - 1ll) * val[x]; return size; } int main() { tot = n = read(),m = read(); for(int i=1;i<=m;i++) { int u = read(),v = read(); G.add(u,v);G.add(v,u); } for(int i=1;i<=n;i++) if(!ins[i]) { sum = 0; Tarjan(i,0); dfs(i,1); } printf("%lld",ans); }