P1600 [NOIP 2016 提高组] 天天爱跑步
P1600 [NOIP 2016 提高组] 天天爱跑步
题目背景
NOIP2016 提高组 D1T2
题目描述
小 C 同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。
这个游戏的地图可以看作一棵包含
现在有
小 C 想知道游戏的活跃度,所以在每个结点上都放置了一个观察员。在结点
注意:我们认为一个玩家到达自己的终点后该玩家就会结束游戏,他不能等待一 段时间后再被观察员观察到。 即对于把结点
Solution:
偶然发现我居然没有写这题的结题报告?赶紧水一发。
首先对于这样的树上路径问题我们都可以把这条路径 (x,y) 拆成上行 (x,lca) 和下行 (lca,y) 两部分:假设一个人睁眼的时间是
我们维护两个桶然后树上差分就好了。
但是还要注意的是,由于我们的桶是全局的,所有我们应该消除子树外的节点的答案对于当前节点的影响。我们在统计答案时应该先算一下统计到这个点时桶的状态
然后这题就做完了。
Code:
#include<bits/stdc++.h> using namespace std; int n,m,cnt,cnta,cnte; const int N=3e5+5; const int lg=20; int head[N],deep[N],fa[N][lg+5],heada[N],heade[N],s[N],e[N],num[N],w[N],dis[N]; struct Edge{ int to,ne; }edge[N<<1]; struct Point{ int id,ne; }lcap[N<<1],endp[N<<1]; void add(int x,int y) { edge[++cnt].to=y;edge[cnt].ne=head[x];head[x]=cnt; } void dfs1(int u,int f) { deep[u]=deep[f]+1; fa[u][0]=f; for(int i=1;i<=lg;i++) { fa[u][i]=fa[fa[u][i-1]][i-1]; } for(int i=head[u];~i;i=edge[i].ne) { int v=edge[i].to; if(v==f)continue; dfs1(v,u); } return ; } int lca(int x,int y) { if(x==y)return x; if(deep[x]<deep[y])swap(x,y); for(int i=lg;i>=0;i--) { if(deep[fa[x][i]]>=deep[y])x=fa[x][i]; } if(x==y)return x; for(int i=lg;i>=0;i--) { if(fa[x][i]!=fa[y][i]){ x=fa[x][i];y=fa[y][i];} } return fa[x][0]; } void adda(int id,int x) { lcap[++cnta].id=id;lcap[cnta].ne=heada[x];heada[x]=cnta; } void adde(int id,int x) { endp[++cnte].id=id;endp[cnte].ne=heade[x];heade[x]=cnte; } void init() { for(int i=1;i<=n;i++) { head[i]=heada[i]=heade[i]=-1; } } int downline[N<<1],upline[N<<1],ans[N]; void dfs2(int u,int f) { int dowm=downline[w[u]-deep[u]+N],up=upline[w[u]+deep[u]];// for(int i=head[u];~i;i=edge[i].ne) { int v=edge[i].to; if(v==f)continue; dfs2(v,u); } upline[deep[u]]+=num[u];//deep[lca]+w=deep[s]; for(int i=heade[u];~i;i=endp[i].ne) { int id=endp[i].id; downline[dis[id]-deep[e[id]]+N]++;//dis=deep[e]-deep[lca]+w; } ans[u]+=downline[w[u]-deep[u]+N]-dowm+upline[w[u]+deep[u]]-up; for(int i=heada[u];~i;i=lcap[i].ne) { int id=lcap[i].id; downline[dis[id]-deep[e[id]]+N]--; upline[deep[s[id]]]--; } return ; } int main() { // freopen("p1600.in","r",stdin); // freopen("p1600.out","w",stdout); cin>>n>>m; init(); for(int i=1,x,y;i<=n-1;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs1(1,1); for(int i=1;i<=n;i++) { scanf("%d",&w[i]); } for(int i=1;i<=m;i++) { scanf("%d%d",&s[i],&e[i]); int a=lca(s[i],e[i]); dis[i]=deep[s[i]]+deep[e[i]]-deep[a]*2; num[s[i]]++; adda(i,a); adde(i,e[i]); if(deep[a]+w[a]==deep[s[i]])ans[a]--; } dfs2(1,1); for(int i=1;i<=n;i++) { printf("%d ",ans[i]); } return 0; }