hdu 6604 DAG上的支配树(灭绝树)
Posted nervendnig
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu 6604 DAG上的支配树(灭绝树)相关的知识,希望对你有一定的参考价值。
http://acm.hdu.edu.cn/showproblem.php?pid=6604
很裸的支配树/灭绝树题
一般图的tarjan算法的话,先建立,反向图,然后建立一个超级源点,然后连到几个起点,跑支配树就行
可惜太慢...过不去
#pragma GCC optimize("Ofast") #include<bits/stdc++.h> #define endl ‘\n‘ #define ll long long #define ull unsigned long long #define fi first #define se second #define mp make_pair #define pii pair<ll,ll> #define all(x) x.begin(),x.end() #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define rep(ii,a,b) for(int ii=a;ii<=b;++ii) #define per(ii,a,b) for(int ii=b;ii>=a;--ii) #define forn(i,x,g,e) for(int i=g[x];i;i=e[i].next) using namespace std;//head const int maxn=1e5+100,maxm=2e5+10; const ll INF=0x3f3f3f3f,mod=1e9+7; int casn,n,m,k,num[maxn],root; class graphpublic://@按点@ struct nodeint to,next;e[maxn]; int head[maxn],nume,ltop[maxn],fa[maxn],deep[maxn],sz[maxn],son[maxn]; inline void add(int a,int b)e[++nume]=b,head[a];head[a]=nume; void init(int n)rep(i,1,n) head[i]=0;nume=0; void dfs1(int now=root,int pre=root,int d=0) deep[now]=d,fa[now]=pre,sz[now]=1,son[now]=0; forn(i,now,head,e) int to=e[i].to; if(to!=pre) dfs1(to,now,d+1); sz[now]+=sz[to]; if(sz[to]>sz[son[now]]) son[now]=to; void dfs2(int now=root,int pre=root,int sp=root) ltop[now]=sp; if(son[now]) dfs2(son[now],now,sp); forn(i,now,head,e) int to=e[i].to; if(to!=son[now]&&to!=pre) dfs2(to,now,to); void getchain()dfs1();dfs2(); int lca(int x,int y) for(;ltop[x]!=ltop[y];deep[ltop[x]]>deep[ltop[y]]?x=fa[ltop[x]]:y=fa[ltop[y]]); return deep[x]<deep[y]?x:y; //@基础部分@ int query(int a,int b) int x=lca(a,b); int ans=deep[a]+deep[b]-deep[x]; return ans; g; class domtreepublic://@dom为最终的支配树,root为根,cnt为每个点的支配点编号和@ int dfn[maxn],rev[maxn],anc[maxn]; int semi[maxn],idom[maxn]; int fa[maxn],mi[maxn],clo; struct nodeint to,next;; struct graph node e[maxn];int head[maxn],nume; void init(int n=maxn-5)nume=0;fill_n(head,n+1,0); void add(int a,int b)e[++nume]=b,head[a];head[a]=nume; inv,nxt,dom; void init(int n=maxn-5) clo=0; rep(i,1,n)fa[i]=mi[i]=semi[i]=i,rev[i]=dfn[i]=anc[i]=idom[i]=0; nxt.init(n),inv.init(n),dom.init(n); void add(int a,int b)inv.add(b,a),nxt.add(a,b); int find(int now) if(fa[now]==now) return now; int fx=fa[now],y=find(fa[now]); if(dfn[semi[mi[fx]]]<dfn[semi[mi[now]]]) mi[now]=mi[fx]; return fa[now]=y; void tdfs(int now) dfn[now]=++clo;rev[clo]=now; forn(i,now,nxt.head,nxt.e)if(!dfn[nxt.e[i].to]) anc[nxt.e[i].to]=now,tdfs(nxt.e[i].to); void maketree(int root,int n=maxn-5) tdfs(root); per(i,2,n) int now=rev[i],tmp=n; forn(i,now,inv.head,inv.e) int to=inv.e[i].to;if(!dfn[to]) continue; if(dfn[to]<dfn[now]) tmp=min(tmp,dfn[to]); else find(to),tmp=min(tmp,dfn[semi[mi[to]]]); semi[now]=rev[tmp];fa[now]=anc[now]; dom.add(semi[now],now); now=rev[i-1]; forn(i,now,dom.head,dom.e) int to=dom.e[i].to;find(to); if(semi[mi[to]]==now) idom[to]=now; else idom[to]=mi[to]; rep(i,2,n) int to=rev[i]; if(idom[to]!=semi[to]) idom[to]=idom[idom[to]]; dom.init(n); rep(i,1,n) if(i!=root)g.add(idom[i],i); tree; int cntin[maxn]; int main() IO; cin>>casn; while(casn--) cin>>n>>m; root=n+1; tree.init(root); g.init(root); rep(i,1,n) cntin[i]=0; rep(i,1,m) int a,b;cin>>a>>b; tree.add(b,a); cntin[a]++; rep(i,1,n)if(!cntin[i])tree.add(root,i); tree.maketree(root,root); g.getchain(); cin>>m; while(m--) int a,b;cin>>a>>b; cout<<g.query(a,b)<<endl;
所以用针对DAG的拓扑排序+倍增做法,就能1000ms以下ac了(一个题套了两个板子..)
#include<bits/stdc++.h> #define ll long long #define ull unsigned long long #define fi first #define endl ‘\n‘ #define se second #define mp make_pair #define pii pair<ll,ll> #define all(x) x.begin(),x.end() #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define rep(ii,a,b) for(int ii=a;ii<=b;++ii) #define per(ii,a,b) for(int ii=b;ii>=a;--ii) #define forn(ii,x) for(int ii=head[x];ii;ii=e[ii].next) #pragma GCC optimize("Ofast") #define forn(i,x,g,e) for(int i=g[x];i;i=e[i].next) const int maxn=3e5+9,maxm=1e9+10,maxp=20; using namespace std; int casn,n,m,k,root; int cntin[maxn]; struct nodeint to,next;; class graphpublic: node e[maxn];int head[maxn],nume; void init(int n=maxn-5)nume=0;fill_n(head,n+1,0); void add(int a,int b)e[++nume]=b,head[a];head[a]=nume; inv,nxt,dom; class domtreepublic://@DAG版本,dom依旧是最终树@ int deep[maxn],anc[maxn][maxp],que[maxn]; vector<int>edge; void init(int n=maxn-5) inv.init(n),nxt.init(n),dom.init(n); edge.clear(); void bit(int &x,int h) for(int i=0;h>0;++i) if(h&1) x=anc[x][i]; h>>=1; int lca(int a,int b) if(deep[a]<deep[b]) swap(a,b); bit(a,deep[a]-deep[b]); if(a==b) return a; per(i,0,maxp-1) if(anc[a][i]!=anc[b][i]) a=anc[a][i],b=anc[b][i]; return anc[a][0]; void tpsort(int n) int tp=0,ed=0; rep(i,1,n) if(!cntin[i]) que[ed++]=i; inv.add(0,i); nxt.add(i,0); edge.push_back(i); while(ed!=tp) int now=que[tp++]; forn(i,now,inv.head,inv.e) int to=inv.e[i].to; cntin[to]--; if(!cntin[to]) que[ed++]=to,edge.push_back(to); void maketree() for(auto i:edge) int fa=-1; forn(j,i,nxt.head,nxt.e) int to=nxt.e[j].to; if(fa==-1) fa=to; else fa=lca(fa,to); fa=fa==-1?0:fa; deep[i]=deep[fa]+1,anc[i][0]=fa; rep(j,1,maxp-1) anc[i][j]=anc[anc[i][j-1]][j-1]; dom.add(fa,i); int query(int a,int b)return deep[a]+deep[b]-deep[lca(a,b)]; tree; int main() IO; cin>>casn; while(casn--) cin>>n>>m; tree.init(n+1); while(m--) int a,b;cin>>a>>b; nxt.add(a,b); inv.add(b,a); cntin[a]++; tree.tpsort(n); tree.maketree(); cin>>m; while(m--) int a,b;cin>>a>>b; cout<<tree.query(a,b)<<endl;
以上是关于hdu 6604 DAG上的支配树(灭绝树)的主要内容,如果未能解决你的问题,请参考以下文章