LOJ2125
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\n",ask(x));
144 }
145 return 0;
146 }
LOJ2125的更多相关文章
随机推荐
- Java学习日报7.10
package Address;import java.util.Scanner; public class Address{ Scanner sc=new Scanner(System.in); p ...
- 线程方法wait()和notify()的使用
实现需求: 开启2个线程,1个线程对某个int类型成员变量加1,另外1个减1,但是要次序执行,即如果int型的成员变量是0,则输出01010101这样的结果 代码如下 1 package test; ...
- [从源码学设计]蚂蚁金服SOFARegistry之服务上线
[从源码学设计]蚂蚁金服SOFARegistry之服务上线 目录 [从源码学设计]蚂蚁金服SOFARegistry之服务上线 0x00 摘要 0x01 业务领域 1.1 应用场景 1.1.1 服务发布 ...
- 2. C++中的引用
1. 引用的基本使用 作用:给变量起别名 语法:数据类型 &别名=原名 注意: 别名数据类型与原名数据类型一致. 引用必须初始化. 引用一旦初始化后,就不可以更改(只能作为一个变量的别名) ...
- SpringBoot整合Shiro权限框架实战
什么是ACL和RBAC ACL Access Control list:访问控制列表 优点:简单易用,开发便捷 缺点:用户和权限直接挂钩,导致在授予时的复杂性,比较分散,不便于管理 例子:常见的文件系 ...
- [开源软件] 腾讯云Linux服务器一键安装LAMP/LNMP/LANMP环境 转
本帖最后由 我本戏子 于 2015-8-13 22:00 编辑OneinStack是非常优秀的一键PHP/JAVA安装脚本,提供以下环境:lnmp(Linux + Nginx+ MySQL+ PHP) ...
- 算法历练之路——入学考试(JAVA)
入学考试 时间限制: 1Sec 内存限制: 128MB 提交: 42 解决: 18 题目描述辰辰是个天资聪颖的孩子,他的梦想是成为世界 上最伟大的医师.为此,他想拜附近最有威望的医师为师.医师为了判断 ...
- Kubernetes官方java客户端之七:patch操作
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- springboot集成轻量级权限认证框架sa-token
sa-token是什么? sa-token是一个JavaWeb轻量级权限认证框架,主要解决项目中登录认证.权限认证.Session会话等一系列由此衍生的权限相关业务.相比于其他安全性框架较容易上手. ...
- 【MyBatis】MyBatis 注解开发
MyBatis 注解开发 文章源码 环境搭建 Mybatis 也可以使用注解开发方式,这样就可以减少编写 Mapper 映射文件. 常用注解说明: @Insert 实现新增 @Update 实现更新 ...