必经点树
jys
posted @ Apr 24, 2014 01:01:27 AM
in 未分类
, 1471 阅读
定义x的半必经点为某个x在DFS树上的祖先y,且保证在y---x路径上删除除端点外的任意一点后仍然存在路径从y到x,令semi(x)为所有y中dfn最小的
考虑半必经点定理:
对于一点y,x∈pre(y):
①dfn[x]<dfn[y],x即为y在DFS树上的祖先,根据定义:if(dfn[x]<dfn[semi[y]])semi[y]=x;
②dfn[x]>dfn[y],x不为y的祖先,此时对于任意x的祖先z,满足dfn[z]>dfn[y]:if(dfn[semi[z]]<dfn[semi[y]])semi[y]=semi[z]
这里有几个地方需要解释一下
一、为什么要dfn[z]>dfn[y]:考虑u=lca(x,y),x所属的是一个较晚被dfs到的子树,如果某个z是x的祖先,且dfn[z]<dfn[y],那么此时z必为y在DFS树上的祖先,那么直接将z删去便可使semi(z)无法到达y,与定义不符
二、这样子获得的semi[y]一定为y的祖先么:x所属的子树较晚被dfs到,故获得的semi必为y的祖先
必经点定理相当直观,不叙述
这玩意就算考也不会太难吧。。。
whoknows
#include <cstdio> #include <iostream> #include <algorithm> using namespace std; #define NN 100001 #define MM 1000000 struct chain { int ver[NN],next[MM<<1],to[MM<<1],tot;bool f[MM<<1]; void addedge(int from,int t,bool v) {next[++tot]=ver[from];to[tot]=t;f[tot]=v;ver[from]=tot;} }G,dom; int dfn[NN],clk,idom[NN],semi[NN],fa[NN],id[NN]; struct Ufs { int p[NN],best[NN]; int getf(int x) { if(x==p[x])return x; int t=getf(p[x]); if(dfn[semi[best[x]]]>dfn[semi[best[p[x]]]])best[x]=best[p[x]]; p[x]=t; return p[x]; } int getbest(int x) {getf(x);return best[x];} }ufs; int n,m; void dfs(int o) { dfn[o]=++clk;id[clk]=o; for(int i=G.ver[o];i;i=G.next[i]) if(!dfn[G.to[i]]&&G.f[i]) {fa[G.to[i]]=o;dfs(G.to[i]);} } bool flag[NN]; void read(int& a) { static char t; t=getchar();a=0; while(t<'0'||t>'9'){t=getchar();} while(t>='0'&&t<='9') {a=a*10+(t-'0');t=getchar();} } int main() { // scanf("%d%d",&n,&m); read(n);read(m); for(int i=1;i<=m;i++) { int a,b;//scanf("%d%d",&a,&b); read(a);read(b); G.addedge(a,b,1); G.addedge(b,a,0); } dfs(1); for(int i=1;i<=n;i++)ufs.p[i]=i,ufs.best[i]=i,semi[i]=i; for(int i=n;i>1;i--) { int tmp=2100000000; for(int t=G.ver[id[i]];t;t=G.next[t]) { if(G.f[t])continue; if(dfn[semi[ufs.getbest(G.to[t])]]<tmp) { tmp=dfn[semi[ufs.getbest(G.to[t])]]; } } semi[id[i]]=id[tmp]; dom.addedge(semi[id[i]],id[i],1); for(int t=dom.ver[fa[id[i]]];t;t=dom.next[t]) { if(dfn[semi[ufs.getbest(dom.to[t])]]<dfn[fa[id[i]]]) idom[dom.to[t]]=ufs.getbest(dom.to[t]); else idom[dom.to[t]]=semi[dom.to[t]]; } dom.ver[fa[id[i]]]=0; ufs.p[id[i]]=fa[id[i]]; } semi[1]=1;idom[1]=0; for(int i=2;i<=n;i++) if(idom[id[i]]!=semi[id[i]]) idom[id[i]]=idom[idom[id[i]]]; int ans=0; for(int i=2;i<=n;i++) if(!flag[idom[i]]){++ans;flag[idom[i]]=true;} printf("%d\n",ans); for(int i=1;i<=n;i++) if(flag[i]) { ans--; if(ans==0)printf("%d\n",i); else printf("%d ",i); } }