1. 程式人生 > >[NOIp2016提高組]天天愛跑步

[NOIp2016提高組]天天愛跑步

秒拍 tin reg git clu getchar() tdi gist lin

題目大意:
  有一棵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提高組]天天愛跑步