[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可能会是负的,因此我们可以将它们整体往右移一些位置。

 #include<cstdio>
#include<cctype>
#include<vector>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'';
while(isdigit(ch=getchar())) x=(((x<<)+x)<<)+(ch^'');
return x;
}
const int N=,logN=;
std::vector<int> e[N];
inline void add_edge(const int &u,const int &v) {
e[u].push_back(v);
e[v].push_back(u);
}
int w[N],dep[N],anc[N][logN];
inline int log2(const float &x) {
return ((unsigned&)x>>&)-;
}
void dfs(const int &x,const int &par) {
dep[x]=dep[par]+;
anc[x][]=par;
for(register int i=;i<=log2(dep[x]);i++) {
anc[x][i]=anc[anc[x][i-]][i-];
}
for(register unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==par) continue;
dfs(y,x);
}
}
inline int lca(int x,int y) {
if(dep[x]<dep[y]) std::swap(x,y);
for(register int i=log2(dep[x]-dep[y]);i>=;i--) {
if(dep[anc[x][i]]>=dep[y]) {
x=anc[x][i];
}
}
if(x==y) return x;
for(register int i=log2(dep[x]);i>=;i--) {
if(anc[x][i]!=anc[y][i]) {
x=anc[x][i];
y=anc[y][i];
}
}
return anc[x][];
}
struct Tag {
bool type;
int val,sgn;
};
std::vector<Tag> tag[N];
int ans[N];
int cnt1[N<<],cnt2[N<<];
void stat(const int &x) {
const int tmp=cnt1[dep[x]+w[x]]+cnt2[dep[x]-w[x]+(N<<)];
for(register unsigned i=;i<tag[x].size();i++) {
const Tag &t=tag[x][i];
(t.type?cnt1:cnt2)[t.val]+=t.sgn;
}
for(unsigned i=;i<e[x].size();i++) {
const int &y=e[x][i];
if(y==anc[x][]) continue;
stat(y);
}
ans[x]=cnt1[dep[x]+w[x]]+cnt2[dep[x]-w[x]+(N<<)]-tmp;
}
int main() {
const int n=getint(),m=getint();
for(register int i=;i<n;i++) {
add_edge(getint(),getint());
}
for(register int i=;i<=n;i++) {
w[i]=getint();
}
dfs(,);
for(register int i=;i<m;i++) {
const int s=getint(),t=getint(),p=lca(s,t),len=dep[s]+dep[t]-(dep[p]<<);
tag[s].push_back((Tag){,dep[s],});
tag[t].push_back((Tag){,dep[t]-len+(N<<),});
tag[p].push_back((Tag){,dep[s],-});
tag[anc[p][]].push_back((Tag){,dep[t]-len+(N<<),-});
}
stat();
for(register int i=;i<n;i++) {
printf("%d ",ans[i]);
}
printf("%d",ans[n]);
return ;
}
上一篇:while 小项目练习


下一篇:java中的访问控制符