支配树
CODECHEF MAY15 GRAPHCNT
求sdom
sdom[u]=fa[u]
dfn[v]>dfn[u] 即(v->u)为横插边或反组边 则有sdom[u]=Min(sdom[u],sdom[x]),x为v到根的路径节点中已连通点中sdom最小的节点
求idom
sdom[u]>=sdom[x] idom[x]=sdom[x]
sdom[u]< sdom[x] idom[x]=idom[u],u为sdom最小的点
#include <cstdio> #include <algorithm> #include <vector> using namespace std; int bt[600001],dfn[600001],cnt,lis[600001],nd[600001],nxt[600001],des[600001],fat[600001]; int fa[600001],mins[600001],minpo[600001],n,m,sdom[600001],idom[600001]; long long size[600001]; vector <int> que[600001]; struct data{ int x,y; }sid[600001]; struct data2{ int x,y,z; }; void addedge(int x,int y){ nxt[++cnt]=nd[x];des[cnt]=y;nd[x]=cnt; } void dfs(int po){ bt[po]=1;dfn[po]=++cnt;lis[cnt]=po; for (int p=nd[po];p!=-1;p=nxt[p]) if (!bt[des[p]]){ dfs(des[p]); fat[des[p]]=po; } } int mycomp(const data a,const data b){ return(dfn[a.y]>dfn[b.y]); } data2 find(int po){ if (fa[po]==po) return((data2){po,mins[po],minpo[po]}); data2 t=find(fa[po]); if (dfn[mins[po]]<dfn[t.y]){ t.y=mins[po];t.z=minpo[po]; }else if (dfn[mins[po]]>dfn[t.y]){ mins[po]=t.y;minpo[po]=t.z; } fa[po]=t.x; return(t); } int main(){ scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) nd[i]=-1; for (int i=1;i<=m;i++){ scanf("%d%d",&sid[i].x,&sid[i].y); addedge(sid[i].x,sid[i].y); } cnt=0; dfs(1); for (int i=1;i<=n;i++) fa[i]=i,mins[i]=n+1; for (int i=1;i<=cnt;i++) mins[lis[i]]=lis[i],minpo[lis[i]]=lis[i]; dfn[n+1]=1e9;idom[1]=1; sort(sid+1,sid+m+1,mycomp); int po=1; for (int i=cnt;i>=1;i--){ while (que[lis[i]].size()){ int t=que[lis[i]][que[lis[i]].size()-1];que[lis[i]].pop_back(); data2 fin=find(t); if (dfn[fin.y]>=dfn[sdom[t]]) idom[t]=sdom[t];else idom[t]=-fin.z; } int mini=n+1,mipo; while (po<=m&&sid[po].y==lis[i]){ data2 fin=find(sid[po].x); if (dfn[fin.y]<dfn[mini]) mini=fin.y; po++; } sdom[lis[i]]=mins[lis[i]]=mini; que[sdom[lis[i]]].push_back(lis[i]); for (int p=nd[lis[i]];p!=-1;p=nxt[p]) if (fat[des[p]]==lis[i]) fa[des[p]]=lis[i]; } for (int i=1;i<=cnt;i++) if (idom[lis[i]]<0) idom[lis[i]]=idom[-idom[lis[i]]]; long long ret=(long long)cnt*(cnt-1)/2; for (int i=1;i<=cnt;i++) size[lis[i]]=1; for (int i=cnt;i>1;i--){ if (idom[lis[i]]!=1) ret-=size[idom[lis[i]]]*size[lis[i]]; size[idom[lis[i]]]+=size[lis[i]]; } printf("%lld\n",ret); }