1. 程式人生 > >4719: [Noip2016]天天愛跑步

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]);
}