# 支配树

CODECHEF MAY15 GRAPHCNT

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;
};

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);
}
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);
}

 
posted @ 2017-12-24 13:40 z1j1n1 阅读(...) 评论(...) 编辑 收藏