NOIP2016 day1T2--BZOJ4719 天天愛跑步--LCA+差分
阿新 • • 發佈:2019-01-23
Description
小c同學認為跑步非常有趣,於是決定製作一款叫做《天天愛跑步》的遊戲。?天天愛跑步?是一個養成類遊戲,需要
玩家每天按時上線,完成打卡任務。這個遊戲的地圖可以看作一一棵包含 N個結點和N-1 條邊的樹, 每條邊連線兩
個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從1到N的連續正整數。現在有個玩家,第個玩家的
起點為Si ,終點為Ti 。每天打卡任務開始時,所有玩家在第0秒同時從自己的起點出發, 以每秒跑一條邊的速度,
不間斷地沿著最短路徑向著自己的終點跑去, 跑到終點後該玩家就算完成了打卡任務。 (由於地圖是一棵樹, 所以
每個人的路徑是唯一的)小C想知道遊戲的活躍度, 所以在每個結點上都放置了一個觀察員。 在結點的觀察員會選
擇在第Wj秒觀察玩家, 一個玩家能被這個觀察員觀察到當且僅當該玩家在第Wj秒也理到達了結點J 。 小C想知道
每個觀察員會觀察到多少人?注意: 我們認為一個玩家到達自己的終點後該玩家就會結束遊戲, 他不能等待一 段時
間後再被觀察員觀察到。 即對於把結點J作為終點的玩家: 若他在第Wj秒重到達終點,則在結點J的觀察員不能觀察
到該玩家;若他正好在第Wj秒到達終點,則在結點的觀察員可以觀察到這個玩家。
將每條從u到v的路徑分成兩部分,一部分從u到lca,一部分從lca到v。
先考慮從u到lca的部分:對於所有在這條鏈上的節點,如果
對於從lca到v的部分:如果
接下來,問題就轉化成求某一個節點所在的鏈中上的
以dep[u]為例,只要維護g[i]表示當前dep[u]=i的節點個數,要將某一條鏈上的某一個值加1,只要將這條鏈的尾端的值加1,並將這條鏈頂端的父節點的值減1即可,由於lca上的節點與如果利用差分來考慮,可能會記重複,所以我們把lca單獨考慮,這樣就應該在這條鏈的頂端的節點的值減1。最後統計的時候就是自底向上統計,又因為g是全域性陣列,所以記的不僅僅是當前節點的子樹的資訊,所以可以先記下統計子樹前的值,統計完以後再用後面的值減去這個值就是答案。
時間複雜度:O(nlogn)
最後附上程式碼:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 300006
#define zero maxn*2
using namespace std;
int _read(){
char ch=getchar();int sum=0;
while(!(ch>='0'&&ch<='9'))ch=getchar();
while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=getchar();
return sum;
}
int n,m,tot,_tot[2],w[maxn],ans[maxn],_lnk[2][maxn],lnk[maxn],_son[2][maxn*2],son[maxn*2],_nxt[2][maxn*2],nxt[maxn*2],
p[2][maxn*2],dep[maxn],hsh1[4*maxn],hsh2[4*maxn],f[maxn][20];
bool vis[maxn];
void add(int x,int y){
nxt[++tot]=lnk[x];son[tot]=y;lnk[x]=tot;
}
void _add(int tt,int x,int y,int z){
_nxt[tt][++_tot[tt]]=_lnk[tt][x];_son[tt][_tot[tt]]=y;p[tt][_tot[tt]]+=z;_lnk[tt][x]=_tot[tt];
}
void dfs(int x){
vis[x]=0;
for(int j=lnk[x];j;j=nxt[j]) if(vis[son[j]]){
dep[son[j]]=dep[x]+1;f[son[j]][0]=x;
dfs(son[j]);
}
}
void work(){
memset(vis,1,sizeof(vis));f[1][0]=1;
dfs(1);
for(int j=1;j<=19;j++)
for(int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
}
int LCA(int x,int y){
if(dep[x]<dep[y])swap(x,y);
for(int j=19;j>=0;j--) if(dep[f[x][j]]>=dep[y])x=f[x][j];
if(x==y)return x;
for(int j=19;j>=0;j--) if(f[x][j]!=f[y][j])x=f[x][j],y=f[y][j];
return f[x][0];
}
void dfs1(int x){
vis[x]=0;int p1=hsh1[zero+dep[x]+w[x]],p2=hsh2[zero+dep[x]-w[x]];
for(int j=_lnk[0][x];j;j=_nxt[0][j])hsh1[_son[0][j]+zero]+=p[0][j];
for(int j=_lnk[1][x];j;j=_nxt[1][j])hsh2[_son[1][j]+zero]+=p[1][j];
for(int j=lnk[x];j;j=nxt[j]) if(vis[son[j]])dfs1(son[j]);
ans[x]+=hsh1[zero+dep[x]+w[x]]-p1+hsh2[zero+dep[x]-w[x]]-p2;
}
int main(){
freopen("running.in","r",stdin);
freopen("running.out","w",stdout);
n=_read();m=_read();
for(int i=1,x,y;i<n;i++)x=_read(),y=_read(),add(x,y),add(y,x);
for(int i=1;i<=n;i++)w[i]=_read();
work();
for(int i=1;i<=m;i++){
int u=_read(),v=_read(),lca=LCA(u,v);
ans[lca]+=(w[lca]+dep[lca]==dep[u]);
_add(0,u,dep[u],1);_add(0,lca,dep[u],-1);
_add(1,v,2*dep[lca]-dep[u],1);_add(1,lca,2*dep[lca]-dep[u],-1);
}
memset(vis,1,sizeof(vis));
dfs1(1);
for(int i=1;i<=n;i++)printf("%d ",ans[i]);
return 0;
}