2 条题解
-
0
让我们对kevin的代码稍加解释
函数dfs1:在树上跑dfs,预处理出每个节点的深度,父节点,以及重儿子。
函数dfs2:跑第二遍dfs,记录dfs序以及dfs序反数组(下标和键值互换),每条重链的顶端。
结构体:线段树,以每个节点的dfs序作为下标,具体原因见后。
函数pushup,bt,change,query,详见线段树。
函数solve:计算两个节点之间路径的节点权值总和,即最终答案。如何计算?注意到dfs2是重儿子优先遍历,一条重链上的节点都是dfs序连续的,只需要在LCA过程中每一次跳跃都计算本条重链的和,跳跃完之后输出答案即可。
-
0
#include<bits/stdc++.h> using namespace std; const int N=5e5+10; #define int long long vector<int>G[N]; int dep[N],fa[N],son[N],siz[N],top[N],dfn[N],_dfn[N],tsp; void dfs1(int x,int f) { dep[x]=dep[f]+1;fa[x]=f;siz[x]=1;int mx=0; for(int y:G[x])if(y!=f) { dfs1(y,x); siz[x]+=siz[y]; if(mx<siz[y])mx=siz[y],son[x]=y; } } void dfs2(int x,int tp) { top[x]=tp;dfn[x]=++tsp;_dfn[tsp]=x; if(son[x])dfs2(son[x],tp); for(int y:G[x])if(y!=fa[x]&&y!=son[x])dfs2(y,y); } #define lc(p) (p<<1) #define rc(p) (p<<1|1) struct node{int l,r,s;}tr[N<<2];int a[N]; void pushup(int p){tr[p].s=tr[lc(p)].s+tr[rc(p)].s;} void bt(int p,int l,int r) { tr[p]={l,r,0}; if(l==r){tr[p].s=a[_dfn[l]];return;} int mid=(l+r)>>1; bt(lc(p),l,mid),bt(rc(p),mid+1,r); pushup(p); } void change(int p,int x,int k) { if(tr[p].r<x||tr[p].l>x)return; if(tr[p].l==tr[p].r) { tr[p].s+=k; return ; } change(lc(p),x,k);change(rc(p),x,k); pushup(p); } int query(int p,int l,int r) { if(tr[p].r<l||tr[p].l>r)return 0; if(l<=tr[p].l&&tr[p].r<=r)return tr[p].s; return query(lc(p),l,r)+query(rc(p),l,r); } int solve(int x,int y) { int ret=0; for(;top[x]!=top[y];x=fa[top[x]]) { if(dep[top[x]]<dep[top[y]])swap(x,y); ret+=query(1,dfn[top[x]],dfn[x]); } if(dep[x]>dep[y])swap(x,y); ret+=query(1,dfn[x],dfn[y]); return ret; } signed main() { ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); int n,q;cin>>n>>q; for(int i=1;i<=n;i++)cin>>a[i]; for(int i=1;i<n;i++) { int x,y;cin>>x>>y;x++,y++; G[x].push_back(y); G[y].push_back(x); } dfs1(1,0);dfs2(1,1); bt(1,1,n); while(q--) { int op,x,y;cin>>op>>x>>y;x++;y++; if(op==0)change(1,dfn[x],y-1); else cout<<solve(x,y)<<'\n'; } return 0; }
- 1
信息
- ID
- 8112
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 7
- 标签
- 递交数
- 19
- 已通过
- 9
- 上传者