算法:LCA,樹上差分+(亂搞)
如果有寫錯的地方請大佬更正
對於100%數據:
u表示起點,v表示終點
對於一條u到v的路徑,先討論LCA!=u&&LCA!=v的情況:
分為u到LCA的路徑和LCA到v的路徑
對於u到LCA的路徑上的點x,當deep[u]-deep[x]=w[x]時,即w[x]+deep[x]=deep[u]時,這條路徑對點x有貢獻;
觀察發現w[x]+deep[x]是定值,所以統計經過x的路徑中,deep[u]=w[x]+deep[x]的路徑條數。
對於LCA到v的路徑上的點x,當deep[u]-2*deep[LCA]+deep[x]=w[x]時,即w[x]-deep[x]=deep[u]-2*deep[lca]時,這條路徑對點x有貢獻;
觀察發現w[x]-deep[x]是定值,所以統計經過x的路徑中,deep[u]-2*deep[lca]=w[x]-deep[x]的路徑條數;
接下來就是統計路徑條數了,用到樹上差分
我們統計的起點(終點)一定在點x子樹內,所以統計x子樹內有多少起點(終點)的值等於所需值
即統計有多少個在點x子樹內的起點的deep[u]的值與deep[x]+w[x]相同
有多少終點的deep[u]-2*deep[lca]與w[x]-deep[x]相同
對於一個值,再u、v上加一個表示這個值+1的標記
考慮到x子樹內的路徑不一定經過x,所以在father[LCA]上加一個標記表示這個值-1
標記用動態數組儲存
然后一遍dfs用兩個桶分別統計,統計時值統一加上n,因為可能出現負數
記錄下dfs到父親節點時自己(也就是父親的兒子)所需值的個數,然后統計完子樹的值之后再做差計算自己
對於LCA==u||LCA==v的情況歸於以上兩類計算,特殊處理一下
另外,對於分裂成兩條鏈LCA可能會被統計兩遍,最后特殊判斷一下,如果被統計了兩遍就減去一遍,
復雜度:
LCA O(mlogn)
dfs統計 O(n)
#include<iostream> #include<cstdio> #include<cstring> #include<vector> #define N 300009 using namespace std; int n,m; vector<int>G[N]; int W[N]; int S[N],T[N],LCA[N]; int father[N],son[N],depth[N]; int heavyson[N],top[N]; int dfs1(int now,int fa){ father[now]=fa; son[now]=1; depth[now]=depth[fa]+1; for(int i=0;i<G[now].size();++i){ if(G[now][i]!=fa){ dfs1(G[now][i],now); son[now]+=son[G[now][i]]; if(son[G[now][i]]>son[heavyson[now]])heavyson[now]=G[now][i]; } } } int dfs2(int now,int first){ top[now]=first; if(!heavyson[now])return 0; dfs2(heavyson[now],first); for(int i=0;i<G[now].size();++i){ if(G[now][i]!=father[now]&&G[now][i]!=heavyson[now])dfs2(G[now][i],G[now][i]); } } int swap(int &a,int &b){ int t=a;a=b;b=t; } int lca(int u,int v){ int tu=top[u],tv=top[v]; while(tu!=tv){ if(depth[tu]<depth[tv]){ swap(tu,tv);swap(u,v); } u=father[tu];tu=top[u]; } if(depth[u]<depth[v])return u; else return v; } int cnt[N]; int T1[N+N],T2[N+N]; struct tag{ int v,siz; }; vector<tag>tag1[N]; vector<tag>tag2[N]; int dfs(int now,int a,int b){ for(int i=0;i<tag1[now].size();++i){ T1[tag1[now][i].v+N]+=tag1[now][i].siz; } for(int i=0;i<tag2[now].size();++i){ T2[tag2[now][i].v+N]+=tag2[now][i].siz; } for(int i=0;i<G[now].size();++i){ int v=G[now][i]; if(v==father[now])continue; dfs(v,T1[W[v]+depth[v]+N],T2[W[v]-depth[v]+N]); } cnt[now]+=T1[W[now]+depth[now]+N]+T2[W[now]-depth[now]+N]-a-b; } int read(){ int r=0,k=1; char c=getchar(); for(;c<'0'||c>'9';c=getchar())if(c=='-')k=-1; for(;c>='0'&&c<='9';c=getchar())r=r*10+c-'0'; return r*k; } int main(){ n=read();m=read(); for(int i=1;i<=n-1;++i){ int x=read(),y=read(); G[x].push_back(y); G[y].push_back(x); } for(int i=1;i<=n;++i)W[i]=read(); for(int i=1;i<=m;++i)S[i]=read(),T[i]=read(); dfs1(1,0),dfs2(1,1); for(int i=1;i<=m;++i)LCA[i]=lca(S[i],T[i]); for(int i=1;i<=m;++i){ if(LCA[i]==T[i]){ tag1[S[i]].push_back((tag){depth[S[i]],1}); tag1[father[T[i]]].push_back((tag){depth[S[i]],-1}); }else if(LCA[i]==S[i]){ tag2[T[i]].push_back((tag){depth[S[i]]-2*depth[LCA[i]],1}); tag2[father[S[i]]].push_back((tag){depth[S[i]]-2*depth[LCA[i]],-1}); }else{ if(W[LCA[i]]+depth[LCA[i]]==depth[S[i]])--cnt[LCA[i]]; tag1[S[i]].push_back((tag){depth[S[i]],1}); tag1[father[LCA[i]]].push_back((tag){depth[S[i]],-1}); tag2[T[i]].push_back((tag){depth[S[i]]-2*depth[LCA[i]],1}); tag2[father[LCA[i]]].push_back((tag){depth[S[i]]-2*depth[LCA[i]],-1}); } } dfs(1,0,0); for(int i=1;i<=n;++i)printf("%d ",cnt[i]); return 0; }