标签:排序 using blog art www tail while scan continue
DAG建立支配树
有向图支配树建立步骤
最终D就是要求的支配树
参考博客:
[1]https://blog.csdn.net/a710128/article/details/49913553
[2]https://www.cnblogs.com/fenghaoran/p/dominator_tree.html
[3]https://www.luogu.org/problemnew/solution/P5180
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5+10;
struct Map{
int head[N],ver[N<<1],nxt[N<<1],cnt;
void reset(){cnt = 0;memset(head,0,sizeof head);}
void link(int x,int y){ver[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;}
}E,G,T,TR,D;
int deg[N],dep[N],dfn[N],id[N],fa[N],f[N][20],semi[N],mm[N],tot,anc[N],ans[N],top[N],cnt,n,m;
void dfs(int x){
dfn[x] = ++tot;id[tot] = x;
for(int i=E.head[x];i;i=E.nxt[i]){
int y = E.ver[i];
if(dfn[y])continue;
dfs(y);T.link(x,y);
//2
anc[y] = x;
}
}
int find(int x){
if(x == fa[x])return x;
int ff = fa[x];fa[x] = find(fa[x]);
if(dfn[semi[mm[ff]]] < dfn[semi[mm[x]]])mm[x] = mm[ff];
return fa[x];
}
int LCA(int x,int y){
if(dep[x] > dep[y])swap(x,y);
for(int i=18;i>=0;i--)if(dep[x] < dep[y] && dep[f[y][i]] >= dep[x])y=f[y][i];
if(x == y)return x;
for(int i=18;i>=0;i--)if(f[x][i] != f[y][i])x=f[x][i],y=f[y][i];
return f[x][0];
}
int getAns(int x){
ans[x] = 1;
for(int i=D.head[x];i;i=D.nxt[i]){
int y = D.ver[i];
getAns(y),ans[x] += ans[y];
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
semi[i] = mm[i] = fa[i] = i;
}
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);
E.link(u,v);G.link(v,u);
}
dfs(1);anc[1] = 0;
for(int i=n;i>=2;i--){
int x = id[i],res = n;
if(!x)continue;
for(int i=G.head[x];i;i=G.nxt[i]){
int y = G.ver[i];
if(!dfn[y])continue;
if(dfn[y] < dfn[x])res = min(res,dfn[y]);
else{
//1.
find(y);res = min(res,dfn[semi[mm[y]]]);
}
}
semi[x] = id[res];fa[x] = anc[x];
T.link(semi[x],x);
}
for(int x=1;x<=n;x++)
for(int i=T.head[x];i;i=T.nxt[i]){
int y = T.ver[i];
TR.link(y,x);deg[y]++;
}
queue<int> q;
for(int i=1;i<=n;i++)if(deg[i]==0)q.push(i);
while(!q.empty()){
int x = q.front();q.pop();
top[++cnt] = x;
for(int i=T.head[x];i;i=T.nxt[i]){
int y = T.ver[i];
if((--deg[y]) == 0)q.push(y);
}
}
for(int i=1;i<=cnt;i++){
int x = top[i],bb = -1;
for(int j=TR.head[x];j;j=TR.nxt[j]){
int y = TR.ver[j];
bb = bb==-1?y:LCA(y,bb);
}
f[x][0] = bb;D.link(bb,x);dep[x] = dep[bb]+1;
for(int j=1;j<=18;j++)f[x][j] = f[f[x][j-1]][j-1];
}
getAns(1);
for(int i=1;i<=n;i++)printf("%d ",ans[i]);
return 0;
}
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5+10;
struct Map{
int head[N],ver[N<<1],nxt[N<<1],cnt;
void reset(){cnt = 0;memset(head,0,sizeof head);}
void link(int x,int y){ver[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;}
}E,G,T,D;
int dfn[N],id[N],fa[N],f[N][20],semi[N],mm[N],tot,anc[N],ans[N],top[N],cnt,n,m,idom[N];
void dfs(int x){
dfn[x] = ++tot;id[tot] = x;
for(int i=E.head[x];i;i=E.nxt[i]){
int y = E.ver[i];
if(dfn[y])continue;
dfs(y);
anc[y] = x;
}
}
int find(int x){
if(x == fa[x])return x;
int ff = fa[x];fa[x] = find(fa[x]);
if(dfn[semi[mm[ff]]] < dfn[semi[mm[x]]])mm[x] = mm[ff];
return fa[x];
}
int getAns(int x){
ans[x] = 1;
for(int i=D.head[x];i;i=D.nxt[i]){
int y = D.ver[i];
getAns(y),ans[x] += ans[y];
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
semi[i] = mm[i] = fa[i] = i;
}
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);
E.link(u,v);G.link(v,u);
}
dfs(1);anc[1] = 0;
for(int i=n;i>=2;i--){
int x = id[i],res = n;
if(!x)continue;
for(int i=G.head[x];i;i=G.nxt[i]){
int y = G.ver[i];
if(!dfn[y])continue;
if(dfn[y] < dfn[x])res = min(res,dfn[y]);
else{
//1.
find(y);res = min(res,dfn[semi[mm[y]]]);
}
}
semi[x] = id[res];fa[x] = anc[x];
T.link(semi[x],x);
x = anc[x];
for(int j=T.head[x];j;j=T.nxt[j]){
int y = T.ver[j];
find(y);
if(semi[mm[y]] == x)idom[y] = x;
else idom[y] = mm[y];
}
}
for(int i=2,now;i<=tot;i++){
now = id[i];
if(idom[now] != semi[now])idom[now] = idom[idom[now]];
}
for(int i=2;i<=n;i++)if(idom[i])D.link(idom[i],i);
getAns(1);
for(int i=1;i<=n;i++)printf("%d ",ans[i]);
return 0;
}
上面两个实际跑出来时间差不多...另外建图也可以不用结构体,多弄几个head数组即可。但是不能用vector,洛谷测模板题会T
19年多校的一个题,DAG上面建支配树,结合LCA容斥求支配树上两点的公共点个数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int N = 200010;
//E:反向图,G原图,T支配树
//dep:T中的深度,deg:反向图中的入度
vector<int> E[N],G[N],T[N];
int n,m,deg[N],rt,a[N],dep[N],val[N];
int f[N][20],tot;
void BFS(){
queue<int> q;
rt = n+1;
for(int i=1;i<=n;i++)if(!deg[i]){q.push(i);E[rt].pb(i);G[i].pb(rt);}
int tot = 0;
while(!q.empty()){
int u = q.front();q.pop();
a[++tot] = u;
for(int v : E[u])if((--deg[v]) == 0)q.push(v);
}
}
int LCA(int x,int y){
if(dep[x] > dep[y])swap(x,y);
for(int i=19;i>=0;i--)if(dep[y] > dep[x] && dep[f[y][i]] >= dep[x])y = f[y][i];
if(x == y)return x;
for(int i=19;i>=0;i--)if(f[x][i] != f[y][i]) x = f[x][i],y=f[y][i];
return f[x][0];
}
int main(){
int tt;scanf("%d",&tt);
while(tt--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n+1;i++){
E[i].clear();G[i].clear();T[i].clear();
dep[i] = deg[i] = 0;
}
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);
E[v].pb(u);G[u].pb(v);deg[u] ++;
}
BFS();
dep[rt] = 1;
for(int i=1;i<=n;i++){
int u = a[i],fa = -1;
for(int v:G[u])fa = (fa == -1 ?v:LCA(fa,v));
dep[u] = dep[fa]+1;
f[u][0] = fa;T[fa].pb(u);
for(int i=1;i<=19;i++)f[u][i] = f[f[u][i-1]][i-1];
}
int q;scanf("%d",&q);
while(q--){
int u,v;scanf("%d%d",&u,&v);
int lca = LCA(u,v);
printf("%d\n",dep[u] + dep[v] - dep[lca] - 1);
}
}
}
标签:排序 using blog art www tail while scan continue
原文地址:https://www.cnblogs.com/1625--H/p/11286941.html