[NOIp2016提高组]天天爱跑步
Posted skylee的OI博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOIp2016提高组]天天爱跑步相关的知识,希望对你有一定的参考价值。
题目大意:
有一棵n个点的树,每个点上有一个摄像头会在第w[i]秒拍照。
有m个人再树上跑,第i个人沿着s[i]到t[i]的路径跑,每秒钟跑一条边。
跑到t[i]的下一秒,人就会消失。
问每个摄像头会拍下几个人。
思路:
首先很显然是要求LCA的。
求完LCA怎么办?
我们可以用树上差分的方法分别维护向上、向下的链。
每一条路径,我们可以在s,t,lca,par[lca]上分别打标记。
s +dep[s]
t +dep[t]-len
lca -dep[s]
par[lca] +len-dep[t]
其中有一些是向上走的链、有一些是向下走的链,因此我们还需要将它们区分开来。
一个点x满足条件当且仅当x在s到lca的路上且dep[x]-dep[s]=w[x],
或者x在lca到t的路上且dep[lca]-dep[s]+deo[lca]-dep[x]=w[x]。
最后从根节点DFS统计一下,访问到x结点就把对应的标记加进去,ans[x]=统计完子树后的答案-统计之前的答案。
另外注意dep[t]-len可能会是负的,因此我们可以将它们整体往右移一些位置。
1 #include<cstdio> 2 #include<cctype> 3 #include<vector> 4 inline int getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int x=ch^‘0‘; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^‘0‘); 9 return x; 10 } 11 const int N=299999,logN=19; 12 std::vector<int> e[N]; 13 inline void add_edge(const int &u,const int &v) { 14 e[u].push_back(v); 15 e[v].push_back(u); 16 } 17 int w[N],dep[N],anc[N][logN]; 18 inline int log2(const float &x) { 19 return ((unsigned&)x>>23&255)-127; 20 } 21 void dfs(const int &x,const int &par) { 22 dep[x]=dep[par]+1; 23 anc[x][0]=par; 24 for(register int i=1;i<=log2(dep[x]);i++) { 25 anc[x][i]=anc[anc[x][i-1]][i-1]; 26 } 27 for(register unsigned i=0;i<e[x].size();i++) { 28 const int &y=e[x][i]; 29 if(y==par) continue; 30 dfs(y,x); 31 } 32 } 33 inline int lca(int x,int y) { 34 if(dep[x]<dep[y]) std::swap(x,y); 35 for(register int i=log2(dep[x]-dep[y]);i>=0;i--) { 36 if(dep[anc[x][i]]>=dep[y]) { 37 x=anc[x][i]; 38 } 39 } 40 if(x==y) return x; 41 for(register int i=log2(dep[x]);i>=0;i--) { 42 if(anc[x][i]!=anc[y][i]) { 43 x=anc[x][i]; 44 y=anc[y][i]; 45 } 46 } 47 return anc[x][0]; 48 } 49 struct Tag { 50 bool type; 51 int val,sgn; 52 }; 53 std::vector<Tag> tag[N]; 54 int ans[N]; 55 int cnt1[N<<2],cnt2[N<<2]; 56 void stat(const int &x) { 57 const int tmp=cnt1[dep[x]+w[x]]+cnt2[dep[x]-w[x]+(N<<1)]; 58 for(register unsigned i=0;i<tag[x].size();i++) { 59 const Tag &t=tag[x][i]; 60 (t.type?cnt1:cnt2)[t.val]+=t.sgn; 61 } 62 for(unsigned i=0;i<e[x].size();i++) { 63 const int &y=e[x][i]; 64 if(y==anc[x][0]) continue; 65 stat(y); 66 } 67 ans[x]=cnt1[dep[x]+w[x]]+cnt2[dep[x]-w[x]+(N<<1)]-tmp; 68 } 69 int main() { 70 const int n=getint(),m=getint(); 71 for(register int i=1;i<n;i++) { 72 add_edge(getint(),getint()); 73 } 74 for(register int i=1;i<=n;i++) { 75 w[i]=getint(); 76 } 77 dfs(1,0); 78 for(register int i=0;i<m;i++) { 79 const int s=getint(),t=getint(),p=lca(s,t),len=dep[s]+dep[t]-(dep[p]<<1); 80 tag[s].push_back((Tag){1,dep[s],1}); 81 tag[t].push_back((Tag){0,dep[t]-len+(N<<1),1}); 82 tag[p].push_back((Tag){1,dep[s],-1}); 83 tag[anc[p][0]].push_back((Tag){0,dep[t]-len+(N<<1),-1}); 84 } 85 stat(1); 86 for(register int i=1;i<n;i++) { 87 printf("%d ",ans[i]); 88 } 89 printf("%d",ans[n]); 90 return 0; 91 }
以上是关于[NOIp2016提高组]天天爱跑步的主要内容,如果未能解决你的问题,请参考以下文章