[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 }

 

posted @ 2017-11-04 20:57  skylee03  阅读(140)  评论(0编辑  收藏  举报