4719: [Noip2016]天天愛跑步
Time Limit: 40 Sec Memory Limit: 512 MB
Submit: 1986 Solved: 752
[Submit][Status][Discuss]
Description
小c同學認為跑步非常有趣,於是決定製作一款叫做《天天愛跑步》的遊戲。?天天愛跑步?是一個養成類遊戲,需要
玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一一棵包含 N個結點和N-1 條邊的樹, 每條邊連線兩
個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從1到N的連續正整數。現在有個玩家,第個玩家的
起點為Si ,終點為Ti 。每天打卡任務開始時,所有玩家在第0秒同時從自己的起點出發, 以每秒跑一條邊的速度,
不間斷地沿著最短路徑向著自己的終點跑去, 跑到終點後該玩家就算完成了打卡任務。 (由於地圖是一棵樹, 所以
每個人的路徑是唯一的)小C想知道遊戲的活躍度, 所以在每個結點上都放置了一個觀察員。 在結點的觀察員會選
擇在第Wj秒觀察玩家, 一個玩家能被這個觀察員觀察到當且僅當該玩家在第Wj秒也理到達了結點J 。 小C想知道
每個觀察員會觀察到多少人?注意: 我們認為一個玩家到達自己的終點後該玩家就會結束遊戲, 他不能等待一 段時
間後再被觀察員觀察到。 即對於把結點J作為終點的玩家: 若他在第Wj秒重到達終點,則在結點J的觀察員不能觀察
到該玩家;若他正好在第Wj秒到達終點,則在結點的觀察員可以觀察到這個玩家。
Input
第一行有兩個整數N和M 。其中N代表樹的結點數量, 同時也是觀察員的數量, M代表玩家的數量。
接下來n-1 行每行兩個整數U和V ,表示結點U 到結點V 有一條邊。
接下來一行N 個整數,其中第個整數為Wj , 表示結點出現觀察員的時間。
接下來 M行,每行兩個整數Si和Ti,表示一個玩家的起點和終點。
對於所有的資料,保證 。
1<=Si,Ti<=N,0<=Wj<=N
Output
輸出1行N 個整數,第個整數表示結點的觀察員可以觀察到多少人。
Sample Input
6 3
2 3
1 2
1 4
4 5
4 6
0 2 5 1 2 3
1 5
1 3
2 6
Sample Output
2 0 0 1 1 1
HINT
對於1號點,W1=0,故只有起點為1號點的玩家才會被觀察到,所以玩家1和玩家2被觀察到,共2人被觀察到。
對於2號點,沒有玩家在第2秒時在此結點,共0人被觀察到。
對於3號點,沒有玩家在第5秒時在此結點,共0人被觀察到。
對於4號點,玩家1被觀察到,共1人被觀察到。
對於5號點,玩家1被觀察到,共1人被觀察到。
對於6號點,玩家3被觀察到,共1人被觀察到
樹上差分
把每一個人的跑步路程分從\(lca\)上成兩段差分到樹根上
對於從下往上跑的人每次\(time++\),\(deep--\)
對於從上往下跑的人每次\(deep--\),\(time++\)
對於一個\(u\)
能在\(T\)時間跑到他的只有他子樹內向上跑\(deep+time=deep_u+T\)的人和向下跑\(deep-time=deep_u-T\)的人
每次新到一個點把現在的值減去,把這個點的貢獻加上,離開這個點時在把值加上
關於每個點的貢獻用vector存即可
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<vector>
#define M 3000001
using namespace std;
int i,m,n,j,k,a[M],ver[M],nex[M],head[M],x,y,cnt,z[M],s[M],d[M];
int wson[M],top[M],f[M],g[M],h[M],ans[M],ti[M];
vector <int>qa[M],pa[M],qd[M],pd[M];
void add(int x,int y)
{
cnt+=1;
ver[cnt]=y; nex[cnt]= head[x]; head[x]=cnt;
}
void dfs1(int x,int fa)
{
f[x]=fa; d[x]=d[fa]+1; s[x]=1;
for(int i=head[x];i;i=nex[i])
{
int t=ver[i];
if(t==fa) continue;
dfs1(t,x);
if(s[t]>s[wson[x]]) wson[x]=t;
s[x]+=s[t];
}
}
void dfs2(int x,int fa)
{
top[x]=fa; if(wson[x]) dfs2(wson[x],fa);
for(int i=head[x];i;i=nex[i])
{
int t=ver[i];
if(!top[t]) dfs2(t,t);
}
}
int lca(int x,int y)
{
while(top[x]!=top[y])
{
if(d[top[x]]<d[top[y]]) swap(x,y);
x=f[top[x]];
}
return d[x]<d[y]?x:y;
}
void dfs(int now)
{
ans[now]=-g[d[now]+ti[now]+300000]-h[d[now]-ti[now]+300000];
for(int i=0;i<qa[now].size();i++) g[qa[now][i]]+=1;
for(int i=0;i<pa[now].size();i++) h[pa[now][i]]+=1;
for(int i=head[now];i;i=nex[i])
{
int t=ver[i];
if(t==f[now]) continue;
dfs(t);
}
for(int i=0;i<qd[now].size();i++) g[qd[now][i]]-=1;
for(int i=0;i<pd[now].size();i++) h[pd[now][i]]-=1;
ans[now]+=g[d[now]+ti[now]+300000]+h[d[now]-ti[now]+300000];
}
int main()
{
scanf("%d%d",&n,&m);
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
for(i=1;i<=n;i++) scanf("%d",&ti[i]);
dfs1(1,0); dfs2(1,1);
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
int t=lca(x,y);
int k=d[x]+d[y]-2*d[t];
qa[x].push_back(d[x]+300000),qd[f[t]].push_back(d[x]+300000);
if(x!=y)pa[y].push_back(d[y]-k+300000),pd[t].push_back(d[y]-k+300000);
}
dfs(1);
for(i=1;i<=n;i++) printf("%d ",ans[i]);
}