LOJ2125

LOJ2125 树上操作

题目描述

有一棵点数为 N 的树,以点 1 为根,且树有点权。然后有 M 个操作,分为三种:

  1. 把某个节点 x 的点权增加 aa 。
  2. 把某个节点 x 为根的子树中所有点的点权都增加 a 。
  3. 询问某个节点 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,M10^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\n",ask(x));
144     }
145     return 0;
146 }
View Code

 

posted on 2019-03-01 10:14  gryzy  阅读(104)  评论(0编辑  收藏  举报

导航