Problem
一张图中有 n n n 个点,之间存在 m m m 个单向的信息传递关系,其中点 n n n 是所有消息的源头。
如果去掉点 b b b,点 n n n 就无法给点 a a a 传递信息,则称 b b b 是 a a a 的 important sister。
求每个点的所有 important sister 的编号之和。
数据范围: 1 ≤ n ≤ 5 × 1 0 4 1 ≤ n ≤ 5\times 10^4 1≤n≤5×104, 0 ≤ m ≤ 1 0 5 0 ≤ m ≤ 10^5 0≤m≤105。
Solution
不难发现,点 x x x 的 important sister 就是点 x x x 的支配点。
于是我们构建出支配树,那么显然,我们要求的答案就是从根到 x x x 这一条链上的点编号之和。
其实这个和统计 s i z e size size 之类的差不多。(具体实现就看代码中 DfsTree)
也是一道比较简单的题。
注意一下,由于有多组数据,一定要注意初始化。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200005
using namespace std;
int n,m,tot;
struct edge{
int t,first[N],v[N],nxt[N];
void add(int x,int y){
nxt[++t]=first[x],first[x]=t,v[t]=y;
}
}G,InvG,Semi,Idom;
int Set[N],Min[N],fa[N],dfn[N],pos[N],semi[N],idom[N],ans[N];
void Clear(){
memset(ans,0,sizeof(ans));
memset(dfn,0,sizeof(dfn));
memset(G.first,0,sizeof(G.first));
memset(InvG.first,0,sizeof(InvG.first));
memset(Semi.first,0,sizeof(Semi.first));
memset(Idom.first,0,sizeof(Idom.first));
G.t=InvG.t=Semi.t=Idom.t=tot=0;
}
int find(int x){
if(Set[x]==x) return x;
int father=find(Set[x]);
if(dfn[semi[Min[Set[x]]]]<dfn[semi[Min[x]]]) Min[x]=Min[Set[x]];
return Set[x]=father;
}
void dfs(int x){
dfn[x]=++tot,pos[tot]=x;
for(int i=G.first[x];i;i=G.nxt[i]){
int to=G.v[i];
if(dfn[to]) continue;
fa[to]=x,dfs(to);
}
}
void Tarjan(){
for(int j=tot;j>1;--j){
int x=pos[j];
for(int i=InvG.first[x];i;i=InvG.nxt[i]){
int to=InvG.v[i];
if(!dfn[to]) continue;
find(to);
if(dfn[semi[Min[to]]]<dfn[semi[x]]) semi[x]=semi[Min[to]];
}
Semi.add(semi[x],x),Set[x]=fa[x];
int now=fa[x];
for(int i=Semi.first[now];i;i=Semi.nxt[i]){
int to=Semi.v[i];find(to);
if(semi[Min[to]]==now) idom[to]=now;
else idom[to]=Min[to];
}
}
for(int i=2;i<=tot;++i){
int x=pos[i];
if(idom[x]!=semi[x]) idom[x]=idom[idom[x]];
Idom.add(idom[x],x);
}
}
void DfsTree(int x){
ans[x]+=x;
for(int i=Idom.first[x];i;i=Idom.nxt[i]){
int to=Idom.v[i];
ans[to]+=ans[x],DfsTree(to);
}
}
int main(){
int x,y,i;
while(~scanf("%d%d",&n,&m)){
Clear();
for(i=1;i<=n;++i)
Set[i]=Min[i]=semi[i]=i;
for(i=1;i<=m;++i){
scanf("%d%d",&x,&y);
G.add(x,y),InvG.add(y,x);
}
dfs(n),Tarjan();
DfsTree(n);
for(i=1;i<=n;++i){
printf("%d",ans[i]);
if(i!=n) putchar(' ');
}
puts("");
}
return 0;
}