2018.11.09【NOIP2016】【洛谷P1600】天天愛跑步(樹上差分)
阿新 • • 發佈:2018-12-20
傳送門
解析:
據說這是NOIP歷年最難一道題。。但是真的沒有寶藏難啊我覺得。。。
思路:
答案分兩類統計,一種是子樹中過來,一種是其他地方過來。那麼路徑就被拆分成兩部分了,一部分是,一部分是,兩部分分別對應兩種答案的統計,這就可以樹上差分了。
第一種:從子樹中經過。設統計答案的點為
子樹中為起點則必須要滿足,即統計子樹內有多少個深度為的點,這個就是樹上差分的基礎應用了。
第二種:從其他子樹來。設統計答案的點為
則需要記錄入答案的路徑需要滿足,不過這個不需要體現在程式碼上。而滿足路徑長度則需要。
這個等式左邊只和有關,右邊和沒有關係,同樣樹上差分解決。
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=300005;
int bin1[N<< 1],bbb[N<<1];
int *cs bin2=bbb+N;
int last[N],nxt[N<<1],to[N<<1],ecnt;
inline void addedge(int u,int v){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;
nxt[++ecnt]=last[v],last[v]=ecnt,to[ecnt]=u;
}
int w[N];
int fa[N],top[N],dep[N],siz[N],son[N];
inline void dfs1(int u){
siz[u]=1;
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa[u])continue;
fa[v]=u;
dep[v]=dep[u]+1;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]])son[u]=v;
}
}
inline void dfs2(int u){
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa[u])continue;
if(son[u]==v)top[v]=top[u];
else top[v]=v;
dfs2(v);
}
}
inline void tree_dissection(int root=1){
dfs1(root);
top[root]=root;
dfs2(root);
}
inline int LCA(int u,int v){
while(top[u]^top[v]){
if(dep[top[u]]>dep[top[v]])swap(u,v);
v=fa[top[v]];
}
return dep[u]>dep[v]?v:u;
}
vector<int> pos1[N],pos2[N],add1[N],add2[N];
int ans[N];
inline void dfs(int u){
int pre1=bin1[dep[u]+w[u]],pre2=bin2[w[u]-dep[u]];
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){
if(v==fa[u])continue;
dfs(v);
}
for(int re i=0;i<pos1[u].size();++i)bin1[pos1[u][i]]+=add1[u][i];
for(int re i=0;i<pos2[u].size();++i)bin2[pos2[u][i]]+=add2[u][i];
ans[u]+=bin1[dep[u]+w[u]]-pre1+bin2[w[u]-dep[u]]-pre2;
}
int n,m;
signed main(){
n=getint();
m=getint();
for(int re i=1;i<n;++i){
int u=getint(),v=getint();
addedge(u,v);
}
tree_dissection();
for(int re i=1;i<=n;++i)
w[i]=getint();
for(int re i=1;i<=m;++i){
int u=getint(),v=getint(),lca=LCA(u,v);
pos1[u].push_back(dep[u]);add1[u].push_back(1);
pos1[lca].push_back(dep[u]);add1[lca].push_back(-1);
pos2[v].push_back(dep[u]-2*dep[lca]);add2[v].push_back(1);
pos2[fa[lca]].push_back(dep[u]-2*dep[lca]);add2[fa[lca]].push_back(-1);
}
dfs(1);
for(int re i=1;i<=n;++i)printf("%d ",ans[i]);
return 0;
}