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,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\n",ask(x));
144 }
145 return 0;
146 }

LOJ2125的更多相关文章

随机推荐

  1. 【Mongodb】后台主键_id自增(Java版本)

    ObjectId的选择 创建MongoDB文档时,如果没有赋值ID,系统会自动帮你创建一个,通常会在客户端由驱动程序完成.得到的ObjectId类似于这种   ObjectId使用12字节的存储空间, ...

  2. 215. Kth Largest Element in an Array找出数组中第k大的值

    堆排序做的,没有全部排序,找到第k个就结束 public int findKthLargest(int[] nums, int k) { int num = 0; if (nums.length &l ...

  3. 使用Arduino点亮ESP-01S,ESP8266-01S上的板载LED

    因为在开发ESP-01s远程控制中觉得接线麻烦,又因为ESP-01s板子上带有LED灯,那就先点亮板载LED,  如图所示: 打开Arduino 把代码copy进去,再编译烧录,就可以看见LED灯每隔 ...

  4. Hive日期函数总结(转学习使用)

    一.时间戳函数 1.获取当前时区的UNIX时间戳:select unix_timestamp(); 2.将指定时间转为UNIX时间戳: select unix_timestamp('2012-03-0 ...

  5. 【C++】《Effective C++》第四章

    第四章 设计与声明 条款18:让接口容易被正确使用,不易被误用 请记住 好的接口很容易被正确使用,不容易被误用.你应该在你的所有接口中努力达到这些性质. "促进正确使用"的办法包括 ...

  6. 天梯赛练习 L3-006 迎风一刀斩 (30分) 几何关系

    题目分析: 对于给出的两个多边形是否可以组成一个矩形,这里我们分以下几种情况讨论 1.首先对于给出的两个多边形只有3-3,3-4,3-5,4-4才有可能组成一个矩形,并且两个多边形只可能是旋转90,1 ...

  7. Flink SQL结合Kafka、Elasticsearch、Kibana实时分析电商用户行为

    body { margin: 0 auto; font: 13px / 1 Helvetica, Arial, sans-serif; color: rgba(68, 68, 68, 1); padd ...

  8. Tomcat的整体架构

    Tomcat通过连接器和容器这两个核心组件完成整体工作,连接器负责处理socket连接和网络字节流与Request和Response对象的转化:容器负责加载和管理Servlet,以及具体处理Reque ...

  9. hugo建站 | 我的第一个博客网站

    前言 博客地址 - https://billie52707.cn 1. 建博客的初衷? 2020那一年,八月的第一天,我还是像往常一样打开我的域名网站,本以为还是会像以前一样显示每日一图的界面,结果出 ...

  10. 十四:SQL注入之类型及提交注入

    简要明确参数类型 数字,字符,搜索,json等 简要明确请求方法 GET,POST,COOKIE,REQUEST,HTTP头 其中SQL语句干扰符号:' " % ) } 等,具体查看用法 非 ...