GDOI2016模拟8.16逃离牛棚
来源:互联网 发布:中级java工程师薪资 编辑:程序博客网 时间:2024/05/21 22:23
题目
现在正是Farmer John的农场里面挤奶的季节了!可是奶牛们全都跑了。FJ需要把他们都圈起来,需要你帮他搜寻奶牛。
FJ的农场里有一排N(1<=N<=200,000)个(编号为1..N)的草场,这N个农场由N-1条双向路连接。牛棚在草场1,而且牛棚能通向任意草场。
FJ的奶牛今天早上都在他们的草场上,但谁知道他们现在跑到哪里去了。FJ知道奶牛们只会从牛棚逃出去,而且他们太懒了所以不能跑超过L的距离。对于每个草场,FJ想知道奶牛们能从这个草场出发能到达的多少个不同的草场,使得奶牛们离牛棚更远。
注意:需要用64位整型存储表示距离的值(int64 in Pascal,long long in C/C++,long in Java)。
这题正难则反(这题是弱化版的,直接上就行,强化版的允许往祖先走,再往下其他分支走)
我们可以将每个点对其他点答案的贡献求出来,即往上距离L以内所有点答案+1,这个可以链剖+线段树(或用数组打标记前缀和,这个少个log)
贴代码
#include<iostream>#include<algorithm>#include<cstdio>#define N 200001using namespace std;int n;long long L;int b[N][2],h[N],f[4*N],g[N],bz[N],fa[N][18],ans[N],bz1[N];long long len[N][18];struct node{ long long dis; int v,next;}a[N];void ins(int x,int y,long long z){ static int sum=0; a[++sum].v=y,a[sum].dis=z,a[sum].next=g[x],g[x]=sum;} void init(){ static int x; long long y; scanf("%d %lld",&n,&L); for (int i=2;i<=n;i++){ scanf("%d %lld",&x,&y); fa[i][0]=x,len[i][0]=y; ins(x,i,y); }}void dfs(int x){ for (int i=0;fa[fa[x][i]][i];fa[x][i+1]=fa[fa[x][i]][i],len[x][i+1]=len[x][i]+len[fa[x][i]][i],i++); for (int i=g[x];i;i=a[i].next){ dfs(a[i].v); if (b[x][0]<b[a[i].v][0]+1) b[x][0]=b[a[i].v][0]+1,b[x][1]=a[i].v; }}void dfs1(int x){ static int sum=0; bz1[bz[x]=++sum]=x; if (b[x][1]) h[b[x][1]]=h[x],dfs1(b[x][1]); for (int i=g[x];i;i=a[i].next) if (a[i].v!=b[x][1]) h[a[i].v]=a[i].v,dfs1(a[i].v);}void pre(){ dfs(1); h[1]=1; dfs1(1);}void change(int l,int r,int s,int ll,int rr){ if (rr<l||r<ll)return; if (ll<=l&&r<=rr){ ++f[s]; return; } change(l,(l+r)/2,s+s,ll,rr); change((l+r)/2+1,r,s+s+1,ll,rr);}void up(int x,int y){ while (true) if (bz[h[x]]<=bz[y]){ change(1,n,1,bz[y],bz[x]); return; }else change(1,n,1,bz[h[x]],bz[x]),x=fa[h[x]][0];}int get(int x){ static int i; static long long y; y=0,i=17; while (y+len[x][0]<=L&&x!=1){ for (;y+len[x][i]>L||!fa[x][i];i--); y+=len[x][i],x=fa[x][i]; } return x;}void build(int l,int r,int s){ if (l==r){ ans[bz1[l]]=f[s]; return; } f[s+s]+=f[s],f[s+s+1]+=f[s]; build(l,(l+r)/2,s+s),build((l+r)/2+1,r,s+s+1);}void work(){ for (int i=1;i<=n;i++) up(i,get(i)); build(1,n,1);}void write(){ for (int i=1;i<=n;i++) printf("%d\n",ans[i]);}int main(){ init(); pre(); work(); write(); return 0;}
0 0
- GDOI2016模拟8.16逃离牛棚
- GDOI2016模拟8.16总结
- GDOI2016模拟8.16帮派
- GDOI2016模拟8.16第一字符串
- GDOI2016模拟8.16打发时间
- GDOI2016模拟8.10踢足球
- GDOI2016模拟8.8旋转
- GDOI2016模拟8.8处理器
- GDOI2016模拟8.13总结
- GDOI2016模拟8.14总结
- GDOI2016模拟8.14数树数
- GDOI2016模拟8.15总结
- GDOI2016模拟8.15蜘蛛侠
- GDOI2016模拟8.15送票
- GDOI2016模拟8.18总结
- GDOI2016模拟8.18蜡笔
- GDOI2016模拟8.18的士
- GDOI2016模拟8.18解密
- kali 2.0安装VM tools
- Oracle学习笔记20150818一些常见查询语句
- Swift环境下实现UILabel居上 居中 居下对齐
- 软件汉化
- DAO设计模式
- GDOI2016模拟8.16逃离牛棚
- Android侧滑菜单
- SparkR
- hibernate 保存图片到数据库(oracle)
- 《Java网络编程》读书笔记(一)
- Linux源代码目录树结构
- 通过ApplicationContextAwareSpring实现手工加载配置的javabean
- python自动登录BAIDU,失效版
- UNIX网络编程卷一:第十七章 ioctl