bzoj 2815 [ZJOI2012]灾难(构造,树形DP)
2016-03-18 09:51
411 查看
【题意】
求把每个点删除后,不可达点的数目。
【思路】
构造一棵“灭绝树”,要求这棵树满足如果删除根节点后则该子树内的所有结点都不可达。则答案为子树大小-1。
如何构造这棵“灭绝树”?
将原图拓扑排序。当我们处理u的时候保证对u的所有食物已经建好树。引入0号节点,以之为所有生产者的食物。设u的食物为v[0..k],当我们至少把v[0..k]的LCA删掉之后u会灭绝,因此由LCA向u连边。增量构造LCA所需信息dep,fa。
鉴于写dfs的时候发生了一些奇奇怪怪的事(包括卡了下bzoj的评测机 lol,就把dfs改成了bfs
【题解链接】
http://fanhq666.blog.163.com/blog/static/8194342620124274154996/
【代码】
求把每个点删除后,不可达点的数目。
【思路】
构造一棵“灭绝树”,要求这棵树满足如果删除根节点后则该子树内的所有结点都不可达。则答案为子树大小-1。
如何构造这棵“灭绝树”?
将原图拓扑排序。当我们处理u的时候保证对u的所有食物已经建好树。引入0号节点,以之为所有生产者的食物。设u的食物为v[0..k],当我们至少把v[0..k]的LCA删掉之后u会灭绝,因此由LCA向u连边。增量构造LCA所需信息dep,fa。
鉴于写dfs的时候发生了一些奇奇怪怪的事(包括卡了下bzoj的评测机 lol,就把dfs改成了bfs
【题解链接】
http://fanhq666.blog.163.com/blog/static/8194342620124274154996/
【代码】
#include<set> #include<cmath> #include<queue> #include<vector> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define trav(u,i,f) for(int i=front[u][f];i;i=e[i][f].nxt) #define FOR(a,b,c) for(int a=(b);a<=(c);a++) using namespace std; typedef long long ll; const int N = 1e5+10; const int M = 2e6+10; const int D = 21; ll read() { char c=getchar(); ll f=1,x=0; while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) x=x*10+c-'0',c=getchar(); return x*f; } struct Edge { int v,nxt; }e[M][2]; int en[2]={1,1},front [2]; void adde(int u,int v,int f) { e[++en[f]][f]=(Edge){v,front[u][f]}; front[u][f]=en[f]; } int n; int in ,fa [D],dep ,siz ; queue<int> q; vector<int> tp; void topo() { FOR(i,1,n) if(!in[i]) q.push(i); while(!q.empty()) { int u=q.front(); q.pop(); tp.push_back(u); trav(u,i,0) { int v=e[i][0].v; if(!(--in[v])) { q.push(v); } } } } int lca(int u,int v) { if(u==-1) return v; if(dep[u]<dep[v]) swap(u,v); int t=dep[u]-dep[v]; FOR(i,0,D-1) if(t&(1<<i)) u=fa[u][i]; if(u==v) return u; for(int i=D-1;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; return fa[u][0]; } void build_tree() { for(int i=tp.size()-1;i>=0;i--) { int u=tp[i]; int lc=-1; trav(u,i,0) lc=lca(lc,e[i][0].v); lc=lc==-1?0:lc; adde(lc,u,1); dep[u]=dep[lc]+1; fa[u][0]=lc; FOR(i,1,D-1) fa[u][i]=fa[fa[u][i-1]][i-1]; } } int vis ; void getans(int u,int fa) { tp.clear(); q.push(0); while(!q.empty()) { int u=q.front(); q.pop(); tp.push_back(u); trav(u,i,1) { int v=e[i][1].v; if(!vis[v]) vis[v]=1,q.push(v); } } for(int i=tp.size()-1;i>=0;i--) { int u=tp[i]; siz[u]=1; trav(u,i,1) siz[u]+=siz[e[i][1].v]; } } int main() { //freopen("in.in","r",stdin); //freopen("out.out","w",stdout); n=read(); int x; FOR(i,1,n) { while(x=read(),x) { adde(i,x,0); in[x]++; } } topo(); build_tree(); getans(0,-1); FOR(i,1,n) printf("%d\n",siz[i]-1); return 0; }
相关文章推荐
- 不使用loop循环,创建一个长度为100的数组,并且每个元素的值等于它的下标
- MyBatis 3.3.1 版本新功能示例
- Java并发编程:Thread类的使用
- 双网卡同时上内外网方法
- Hexo Docs基本用法
- 字符串模式匹配
- C++代码重用——包含
- leetcode-2 Add Two Numbers
- JAVA数组的指针特性
- 结构体使用注意
- 视频基础知识-封装格式和编码格式
- Git的使用
- Tomcat的配置和项目的部署
- 日常问题总结
- java单例模式
- 反射之获得子类及其超类定义的属性和方法
- jquery下拉菜单打开的同时,同行右边的图标变化
- android开发 ArrayList用法
- SVG_点坐标转换
- ubuntu系统查找命令