[bzoj 4034][HAOI 2015]树上操作
Description
Input
Output
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
Sample Input
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
Sample Output
9
13
HINT
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。
题解:
首先看到操作三就能想到树链剖分吧?
再看看题面就能想到线段树维护吧?
然后就没难度了吧?
考虑一下每个操作的做法:
操作1:单点修改,直接在线段树上面修改就好
操作2:把以x为根的子树+a,这是唯一有难度的一个地方。那么想一想我们是怎么剖分这棵树的——两次dfs,也就是说我们的树是按dfs序来构建的,再想想dfs序,它有一个很有趣的性质:
一个子树的编号一定是连续的
证明可以自己去找找。网上有的。
那么当我们想到这个性质之后操作2就不难了,第一次dfs的时候我们已经维护出来一个siz数组表示该节点的子节点了,我们只需要对pos[x],pos[x]+siz[x]-1这个区间进行区间修改就可以了(pos数组是树上的节点在线段树中的编号)
操作3:树链剖分的基本操作,爬到同一条重链上然后区间修改就好了
Code:
#include <cstdio>
#include <cstring>
#define ll long long
#define inf 1<<30
#define il inline
il ll max(ll x,ll y){return x>y?x:y;}
il ll min(ll x,ll y){return x<y?x:y;}
il ll abs(ll x){return x>?x:-x;}
il void swap(ll &x,ll &y){ll t=x;x=y;y=t;}
il void read(ll &x){
x=;ll f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-f;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
x*=f;
}
il void print(ll x){if(x<)putchar('-');x=abs(x);if(x>)print(x/);putchar(x%+'');}
il void writeln(ll x){if(x<)putchar('-');x=abs(x);print(x);putchar('\n');}
il void write(ll x){if(x<)putchar('-');x=abs(x);print(x);putchar(' ');}
using namespace std;
/*===================Header Template=====================*/
#define N 100010
struct tree{ll l,r,sum,tag;}t[N<<];
struct data{ll to,next;}e[N<<];
ll n,m,root,pos[N],sz;
ll cnt,head[N],v[N],v1[N];
ll fa[N],siz[N],top[N],dep[N];
void insert(ll u,ll v){
e[++cnt].to=v;e[cnt].next=head[u];head[u]=cnt;
e[++cnt].to=u;e[cnt].next=head[v];head[v]=cnt;
}
void dfs1(ll x){
siz[x]=;
for(ll i=head[x];i;i=e[i].next){
if(e[i].to==fa[x])continue;
fa[e[i].to]=x;
dep[e[i].to]=dep[x]+;
dfs1(e[i].to);
siz[x]+=siz[e[i].to];
}
}
void dfs2(ll x,ll topf){
top[x]=topf;
pos[x]=++sz;
v1[sz]=v[x];
ll k=;
for(ll i=head[x];i;i=e[i].next){
if(dep[e[i].to]>dep[x]&&siz[e[i].to]>siz[k])k=e[i].to;
}
if(!k)return;
dfs2(k,topf);
for(ll i=head[x];i;i=e[i].next){
if(k!=e[i].to&&dep[e[i].to]>dep[x])dfs2(e[i].to,e[i].to);
}
}
void build(ll l,ll r,ll rt){
t[rt].l=l;t[rt].r=r;
ll mid=(l+r)>>;
if(l==r){return;}
build(l,mid,rt<<);
build(mid+,r,rt<<|);
t[rt].sum=t[rt<<].sum+t[rt<<|].sum;
}
void pushdown(ll ln,ll rn,ll rt){
if(t[rt].tag){
ll &x=t[rt].tag;
t[rt<<].tag+=x;
t[rt<<|].tag+=x;
t[rt<<].sum+=x*ln;
t[rt<<|].sum+=x*rn;
x=;
}
}
void upd1(ll L,ll c,ll rt){
ll l=t[rt].l,r=t[rt].r,mid=(l+r)>>;
if(l==r){t[rt].sum+=c;return;}
pushdown(mid-l+,r-mid,rt);
if(L<=mid)upd1(L,c,rt<<);
else upd1(L,c,rt<<|);
t[rt].sum=t[rt<<].sum+t[rt<<|].sum;
}
void upd2(ll L,ll R,ll c,ll rt){
ll l=t[rt].l,r=t[rt].r,mid=(l+r)>>;
if(L<=l&&r<=R){t[rt].sum+=(r-l+)*c;t[rt].tag+=c;return;}
pushdown(mid-l+,r-mid,rt);
if(L<=mid)upd2(L,R,c,rt<<);
if(R>mid)upd2(L,R,c,rt<<|);
t[rt].sum=t[rt<<].sum+t[rt<<|].sum;
}
ll query(ll L,ll R,ll rt){
ll l=t[rt].l,r=t[rt].r,mid=(l+r)>>,ans=;
if(L<=l&&r<=R)return t[rt].sum;
pushdown(mid-l+,r-mid,rt);
if(L<=mid)ans+=query(L,R,rt<<);
if(R>mid)ans+=query(L,R,rt<<|);
return ans;
}
ll solve_query(ll x,ll y){
ll sum=;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
sum+=query(pos[top[x]],pos[x],);
x=fa[top[x]];
}
if(pos[x]>pos[y])swap(x,y);
sum+=query(pos[x],pos[y],);
return sum;
}
int main(){
read(n);read(m);
for(ll i=;i<=n;i++)read(v[i]);
for(ll i=;i<n;i++){
ll x,y;
read(x);read(y);
insert(x,y);
}
dfs1();dfs2(,);
build(,n,);
for(ll i=;i<=n;i++)upd1(pos[i],v[i],);
while(m--){
ll pd,x,y;
read(pd);read(x);
if(pd==){
read(y);
upd1(pos[x],y,);
}else if(pd==){
read(y);
upd2(pos[x],pos[x]+siz[x]-,y,);
}else if(pd==){
writeln(solve_query(x,));
}
}
return ;
}
转载请注明出处:https://www.cnblogs.com/henry-1202/p/9129614.html
[bzoj 4034][HAOI 2015]树上操作的更多相关文章
- cogs 1963. [HAOI 2015] 树上操作 树链剖分+线段树
1963. [HAOI 2015] 树上操作 ★★★☆ 输入文件:haoi2015_t2.in 输出文件:haoi2015_t2.out 简单对比时间限制:1 s 内存限制:256 M ...
- 洛谷P3178[HAOI]2015 树上操作
题目 树剖裸题,这个题更可以深刻的理解树剖中把树上的节点转换为区间的思想. 要注意在区间上连续的节点,一定是在一棵子树中. #include <bits/stdc++.h> #define ...
- 【BZOJ 4034】[HAOI2015]树上操作 差分+dfs序+树状数组
我们只要看出来这道题 数组表示的含义就是 某个点到根节点路径权值和就行 那么我们可以把最终答案 看做 k*x+b x就是其深度 ,我们发现dfs序之后,修改一个点是差分一个区间,修改一个点的子树,可以 ...
- [HAOI 2015]树上染色
Description 题库链接 给出一棵 \(n\) 个节点的树,边有权值.让你将树上 \(k\) 个点染黑,剩余 \(n-k\) 个点染白.染色后记一种染色方案的价值为黑点间两两距离和以及白点间两 ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4352 Solved: 1387[Submit][Stat ...
- bzoj 4034: [HAOI2015]树上操作 (树剖+线段树 子树操作)
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 6779 Solved: 2275[Submit][Stat ...
- [BZOJ]4034: [HAOI2015]树上操作
[HAOI2015]树上操作 传送门 题目大意:三个操作 1:a,b,c b节点权值+c 2:a,b,c 以b为根的子树节点权值全部+c 3:a,b 查询b到根路径的权值和. 题解:树链剖分 操作1 ...
- [BZOJ 4034] 树上操作
Link: BZOJ 4034 传送门 Solution: 树剖模板题…… Code: #include <bits/stdc++.h> using namespace std; type ...
随机推荐
- Sitecore CMS中更改项目的模板
如何在Sitecore CMS中创建项目后更改项目的模板. 在创建项目时选择了错误的模板,或者创建了新模板并将现有项目更新为新模板时,这非常有用. 警告! 更改模板时要小心.如果原始模板具有不在新 ...
- Sitecore 8.1 - 特性和功能
营销基础 一个新的Sitecore品牌术语取代了体验营销(以前的Sitecore DMS),这是Sitecore体验数据库(xDB)现在所在的位置. Sitecore 7.5和Sitecore 8.0 ...
- Spark学习之路 (四)Spark的广播变量和累加器
一.概述 在spark程序中,当一个传递给Spark操作(例如map和reduce)的函数在远程节点上面运行时,Spark操作实际上操作的是这个函数所用变量的一个独立副本.这些变量会被复制到每台机器上 ...
- plsql 代码自动补全
1.新建一个文件,命名不限定,文件内容为自动补全内容,比如: i=INSERTu=UPDATEs=SELECTf=FROMw=WHEREo=ORDER BYd=DELETEdf=DELETE FROM ...
- python 内置函数enumerate()
enumerate() 函数用于将一个可遍历的数据对象(如列表.元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中.在python 3中返回一个生成器,代码如下: a ...
- JS中的函数节流throttle详解和优化
JS中的函数节流throttle详解和优化在前端开发中,有时会为页面绑定resize事件,或者为一个页面元素绑定拖拽事件(mousemove),这种事件有一个特点,在一个正常的操作中,有可能在一个短的 ...
- 证券化代币的时代已经到来,STO将引爆区块链经济
STOs 似乎会在 2019 年取代 ICOs,即使不是完全取代,但置换的比例也会相当大.所有在美上市的公司都将按照 SEC 制定的相关规定进行交易.Vellum Capital 的 CEO 兼管理合 ...
- [转载]ViewPort <meta>标记
ViewPort <meta>标记用于指定用户是否可以缩放Web页面,如果可以,那么缩放到的最大和最小缩放比例是什么.使用 ViewPort <meta>标记还表示文档针对移动 ...
- 面试必问之JVM篇
前言 只有光头才能变强 JVM在准备面试的时候就有看了,一直没时间写笔记.现在到了一家公司实习,闲的时候就写写,刷刷JVM博客,刷刷电子书. 学习JVM的目的也很简单: 能够知道JVM是什么,为我们干 ...
- css相关知识点
一.CSS的引入方式 1.1 css的介绍 HTML:超文本标记语言.从语义的角度描述页面结构. CSS:层叠样式表.从审美的角度负责页面样式. JS:JavaScript .从交互的角度描述页面行为 ...