bzoj 2815(LCA+拓扑排序)(灭绝树)

来源:互联网 发布:程序员项目描述怎么写 编辑:程序博客网 时间:2024/05/17 04:22

传送门

题意:

在一个DAG中,问一个点是多少个点的支配点?

题解:

好像灭绝树就是因为这题被发明的。在DAG上拓扑排序时,通过在反图上倍增计算所有前驱的LCA,在新图(灭绝树)中add_edge(LCA,当前点)。最后对于每个点输出它在灭绝树上的子树大小-1(自己不算)。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<vector>#include<queue>using namespace std;const int MAXN=65540;vector<int > g[MAXN],rg[MAXN],mg[MAXN];int n,ind[MAXN],siz[MAXN];int pre[MAXN],tot;inline int read() {int x=0;char c=getchar();while (c<'0'||c>'9') c=getchar();while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();return x;}int f[18][MAXN],dep[MAXN];inline int lca(int x,int y) {if (dep[x]<dep[y]) x^=y^=x^=y;int t=dep[x]-dep[y];for (int i=0;i<18;++i)if (t&(1<<i)) x=f[i][x];if (x==y) return x;for (int i=17;~i;--i)if (f[i][x]^f[i][y]) x=f[i][x],y=f[i][y];return f[0][x];}inline void topological_sort() {queue<int > q;while (!q.empty()) q.pop();g[0].clear(),mg[0].clear(),dep[0]=0;for (register int i=1;i<=n;++i)if (!ind[i]) q.push(i),dep[i]=1,g[0].push_back(i),rg[i].push_back(0),f[0][i]=0;while (!q.empty()) {tot=0;int cur=q.front();q.pop();for (int i=0;i<rg[cur].size();++i) {int v=rg[cur][i];pre[++tot]=v;}int anc=pre[1];for (int i=2;i<=tot;++i) anc=lca(anc,pre[i]);dep[cur]=dep[anc]+1;f[0][cur]=anc;//printf("%d->%d\n",anc,cur);mg[anc].push_back(cur);for (int i=1;i<18;++i) f[i][cur]=f[i-1][f[i-1][cur]];for (int i=0;i<g[cur].size();++i) {int v=g[cur][i];--ind[v];if (!ind[v]) q.push(v);}}}void dfs(int p) {siz[p]=1;for (int i=0;i<mg[p].size();++i) {int v=mg[p][i];if (v^f[0][p])dfs(v),siz[p]+=siz[v];}}int main() {//freopen("bzoj 2815.in","r",stdin);memset(ind,0,sizeof(ind));n=read();for (register int i=1;i<=n;++i) g[i].clear(),rg[i].clear(),mg[i].clear();for (register int i=1;i<=n;++i) {while (1) {int x=read();if (!x) break;++ind[i];g[x].push_back(i),rg[i].push_back(x);}}topological_sort();dfs(0);for (register int i=1;i<=n;++i) printf("%d\n",siz[i]-1);return 0;}


原创粉丝点击