【NOIP2016提高Day1】天天愛跑步
阿新 • • 發佈:2018-11-01
題解:
LCA + 樹上差分。對於一次詢問u到v,我們可以拆成兩段,一段為u到LCA,一段為LCA到v。
先考慮u到LCA,即從下到上的情況。對於在i點的觀察員,只有深度在Depth[i] + W[i]的點才可能對i點有貢獻,這個貢獻在LCA點結束。那麼利用差分思想,我們在Depth[i] + W[i]的點打上標記,在LCA處減去標記,則u到LCA這一段就有了1的貢獻。當我們DFS到一個節點x時,需要求的答案是x子樹中節點的貢獻,即回溯完成後標記陣列的變化量,我們在遞迴前儲存一下初始值,去子樹逛一圈後得到新的值,用新的值減去舊的就是變化量了。
那麼LCA到v的情況與上述情況相反,即從上往下,但思想是一樣的,因為Depth[i] - W[i]可能為負數,我們需要加上一個相同的偏移量防止程式執行錯誤。
程式碼:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> #include<queue> #include<climits> #include<cmath> #define MAXA 1000005 using namespace std; int Head[MAXA],cnt; struct Rx_Graph { int next,to; }Edge[MAXA]; struct Rx { int Type,Val,Flag; }; vector<Rx> Gx[MAXA]; Rx Make(int a,int b,int c) { Rx Ret; Ret.Type = a; Ret.Val = b; Ret.Flag = c; return Ret; } void Add(int u,int v) { Edge[++cnt].next = Head[u]; Edge[cnt].to = v; Head[u] = cnt; } int Depth[MAXA],f[MAXA][20],Py = 30000; int LCA(int x,int y) { if(Depth[y] > Depth[x]) swap(x,y); for(int i=18;i>=0;i--) if(Depth[f[x][i]] >= Depth[y]) x = f[x][i]; if(x == y) return x; for(int i=18;i>=0;i--) if(f[x][i] != f[y][i]) { x = f[x][i]; y = f[y][i]; } return f[x][0]; } void Init(int x,int Last) { for(int i=Head[x];i;i=Edge[i].next) { int y = Edge[i].to; if(y == Last) continue; Depth[y] = Depth[x] + 1; f[y][0] = x; Init(y,x); } } void Chafen(int u,int v) { int Lca = LCA(u,v),Len = Depth[u] + Depth[v] - Depth[Lca] * 2; Gx[u].push_back(Make(1,Depth[u],1)); Gx[v].push_back(Make(2,Depth[v] - Len + Py,1)); Gx[Lca].push_back(Make(1,Depth[u],-1)); Gx[f[Lca][0]].push_back((Make(2,Depth[v] - Len + Py,-1))); } int n,m,u,v,CheckTime[MAXA],Start,Target,Cnt1[MAXA],Cnt2[MAXA],Ans[MAXA]; void DFS(int x,int Last) { int Now = Cnt1[CheckTime[x] + Depth[x]] + Cnt2[Depth[x] - CheckTime[x] + Py]; for(int i=0;i<Gx[x].size();i++) { if(Gx[x][i].Type == 1) Cnt1[Gx[x][i].Val] += Gx[x][i].Flag; else Cnt2[Gx[x][i].Val] += Gx[x][i].Flag; } for(int i=Head[x];i;i=Edge[i].next) { int y = Edge[i].to; if(y == Last) continue; DFS(y,x); } Ans[x] = Cnt1[CheckTime[x] + Depth[x]] + Cnt2[Depth[x] - CheckTime[x] + Py] - Now; } int main() { scanf("%d %d",&n,&m); for(int i=1;i<n;i++) { scanf("%d %d",&u,&v); Add(u,v); Add(v,u); } for(int i=1;i<=n;i++) scanf("%d",&CheckTime[i]); Depth[1] = 1; Init(1,0); for(int j=1;j<=18;j++) for(int i=1;i<=n;i++) f[i][j] = f[f[i][j-1]][j-1]; for(int i=1;i<=m;i++) { scanf("%d %d",&Start,&Target); Chafen(Start,Target); } DFS(1,0); for(int i=1;i<=n;i++) printf("%d ",Ans[i]); }