LOJ2125 树上操作
题目描述
有一棵点数为 N 的树,以点 1 为根,且树有点权。然后有 M 个操作,分为三种:
- 把某个节点 x 的点权增加 aa 。
- 把某个节点 x 为根的子树中所有点的点权都增加 a 。
- 询问某个节点 x 到根的路径中所有点的点权和。
输入格式
第一行包含两个整数 N, M。表示点数和操作数。
接下来一行 N 个整数,表示树中节点的初始权值。
接下来 N-1 行每行两个正整数 fr,to , 表示该树中存在一条边(fr,to) 。
再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类(1
-3
) ,之后接这个操作的参数(x
或者 x a
) 。
输出格式
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
样例
样例输入
5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3
样例输出
6
9
13
数据范围与提示
对于 100% 的数据, N,M≤10^5 ,且所有输入数据的绝对值都不会超过 10^6 。
________________________________________________________________________________________
简单的树链剖分,而且树上的查询也比较简单,只是从某个节点到根的权值和。需要注意的如何处理子树的权值修改。这个就是用到了DFS序。需要记录每个点为跟的子树在线段树中左右边界。
________________________________________________________________________________________
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const ll maxn=1e5+10; 5 ll n,m; 6 ll w[maxn]; 7 struct edge 8 { 9 int u,v,nxt; 10 }e[maxn<<1]; 11 ll head[maxn],js; 12 void addage(ll u,ll v) 13 { 14 e[++js].u=u;e[js].v=v; 15 e[js].nxt=head[u];head[u]=js; 16 } 17 ll dep[maxn],siz[maxn],fat[maxn],son[maxn]; 18 void dfs(int u,int fa) 19 { 20 siz[u]=1; 21 dep[u]=dep[fa]+1; 22 fat[u]=fa; 23 for(ll i=head[u];i;i=e[i].nxt) 24 { 25 ll v=e[i].v; 26 if(v==fa)continue; 27 dfs(v,u); 28 siz[u]+=siz[v]; 29 if(!son[u] || siz[son[u]]<siz[v])son[u]=v; 30 } 31 } 32 ll lp[maxn],rp[maxn],top[maxn],fos[maxn],p; 33 void getpos(ll u,ll fa) 34 { 35 lp[u]=++p; 36 fos[p]=u; 37 top[u]=fa; 38 if(!son[u]) 39 { 40 rp[u]=p; 41 return; 42 } 43 getpos(son[u],fa); 44 for(ll i=head[u];i;i=e[i].nxt) 45 { 46 ll v=e[i].v; 47 if(v!=fat[u] && v!=son[u])getpos(v,v); 48 } 49 rp[u]=p; 50 } 51 ll sum[maxn<<2],delt[maxn<<2]; 52 inline void updat(ll cur) 53 { 54 sum[cur]=sum[cur<<1]+sum[cur<<1|1]; 55 } 56 void build(ll cur,ll l,ll r) 57 { 58 if(l==r) 59 { 60 sum[cur]=w[fos[l]]; 61 return; 62 } 63 ll mid=(l+r)>>1; 64 build(cur<<1,l,mid); 65 build(cur<<1|1,mid+1,r); 66 updat(cur); 67 } 68 void down(ll cur,ll l,ll r) 69 { 70 ll mid=(l+r)>>1; 71 delt[cur<<1]+=delt[cur]; 72 delt[cur<<1|1]+=delt[cur]; 73 sum[cur<<1]+=delt[cur]*(mid-l+1); 74 sum[cur<<1|1]+=delt[cur]*(r-mid); 75 delt[cur]=0; 76 } 77 void add(ll cur,ll l,ll r,ll p,ll x) 78 { 79 if(l==r) 80 { 81 sum[cur]+=x; 82 return ; 83 } 84 ll mid=(l+r)>>1; 85 if(delt[cur])down(cur,l,r); 86 if(p<=mid)add(cur<<1,l,mid,p,x); 87 else add(cur<<1|1,mid+1,r,p,x); 88 updat(cur); 89 } 90 void add_(ll cur,ll l,ll r,ll ql,ll qr,ll x) 91 { 92 if(ql<=l && r<=qr) 93 { 94 sum[cur]+=(r-l+1)*x; 95 delt[cur]+=x; 96 return ; 97 } 98 down(cur,l,r); 99 ll mid=(l+r)>>1; 100 if(ql<=mid)add_(cur<<1,l,mid,ql,qr,x); 101 if(mid<qr)add_(cur<<1|1,mid+1,r,ql,qr,x); 102 updat(cur); 103 } 104 ll query(ll cur,ll l,ll r,ll ql,ll qr) 105 { 106 if(ql<=l && r<=qr)return sum[cur]; 107 ll ans=0,mid=(l+r)>>1; 108 if(delt[cur])down(cur,l,r); 109 if(ql<=mid)ans+=query(cur<<1,l,mid,ql,qr); 110 if(mid<qr)ans+=query(cur<<1|1,mid+1,r,ql,qr); 111 return ans; 112 } 113 ll ask(ll x) 114 { 115 ll ans=0; 116 while(x) 117 { 118 ll tpx=top[x]; 119 ans+=query(1,1,n,lp[tpx],lp[x]); 120 x=fat[tpx];tpx=top[x]; 121 } 122 return ans; 123 } 124 int main() 125 { 126 scanf("%lld%lld",&n,&m); 127 for(int i=1;i<=n;++i)scanf("%lld",w+i); 128 for(ll u,v,i=1;i<n;++i) 129 { 130 scanf("%lld%lld",&u,&v); 131 addage(u,v);addage(v,u); 132 } 133 dfs(1,0); 134 getpos(1,1); 135 build(1,1,n); 136 while(m--) 137 { 138 ll x,a,op; 139 scanf("%lld%lld",&op,&x); 140 if(op!=3)scanf("%lld",&a); 141 if(op==1)add(1,1,n,lp[x],a); 142 else if(op==2)add_(1,1,n,lp[x],rp[x],a); 143 else printf("%lld ",ask(x)); 144 } 145 return 0; 146 }