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中自定义一个异常类 在某些情况抛出自定的异常 ----------阻断程序
//=============定义异常类 package org.springblade.flow.engine.errorException; /** * 自定义异常处理写入sap失败 */ pub ...
- ArrayList的删除姿势你都知道了吗
引言 前几天有个读者由于看了<ArrayList哪种遍历效率最好,你真的弄明白了吗?>问了个问题普通for循环ArrayList为什么不能删除连续重复的两个元素?其实这个描述是不正确的.正 ...
- C#设计模式——建造者模式(Builder Pattern)
1.建造者模式简介 1.1>.定义 建造者模式(Builder)将复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. 1.2>.使用频率 中低 1.3>.原型模式应用 ...
- UDP 通讯方式
1.创建套接字:2.绑定端口:3.收发数据: 收到的数据中包含发送方的端口信息4.关闭套接字:
- uniapp H5引入腾讯地图
在网上搜索了许多关于uniapp引入腾讯地图的方法都以失败告终,我开发的应用主要使用于H5,小程序与H5是不同的sdk,就不在这说了,况且小程序有手把手教学,可参考腾讯地图官网https://lbs. ...
- C#自定义控件的应用(数据绑定,属性等)
刚刚开始程序设计的码农生涯,也许一些开发工具上的控件可以满足我们的需求,但是随之时间的迁移,我们对控件的呈现形式需求越来越多样化,这个时候就需要我们来自定义控件,我是一个刚刚入职没多久的菜鸟,接触软件 ...
- DB2在渗透中的应用(转载)
原文地址:http://drops.wooyun.org/tips/16673 0x00 DB2简介 DB2是IBM公司推出关系型数据库管理系统. 现今DB2主要包含以下三个系列: DB2 for L ...
- 使用sublime text3搭建Python编辑环境
最近在工作遇到一个难题. 我所在的测试组有一套PC软件前端自动化工程,在进行自动化测试时,需要在一台古老的xp机器上运行,但这台古老的xp机器带给我诸多烦恼,特别是使用Pycharm编辑器时,我遇到了 ...
- three.js canvas内场景生成图片 canvas生成图片
第一种最简单的方法: 1 threeBox.render();//重点 解决拿到图片后为黑色 2 3 let src=threeBox.renderer.domElement.toDataURL(); ...
- 【Flutter】可滚动组件简介
前言 当组件内容超过当前显示视口(ViewPort)时,如果没有特殊处理,Flutter则会提示Overflow错误.为此,Flutter提供了多种可滚动组件(Scrollable Widget)用于 ...