【NOIP2016提高Day1】天天爱跑步

xiaoxiao2025-08-29  15

魔鬼题面

题解:

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

 

转载请注明原文地址: https://www.6miu.com/read-5035406.html

最新回复(0)