BZOJ 4034 [HAOI2015]树上操作 线段树+树剖或dfs
题意
直接照搬原题面
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
分析
先树剖一下,按重新编号的点建线段树
操作1:直接单点修改
操作2:一个子树里的点的编号是连在一起的,直接区间修改
操作3:该点的\(top\)不为1时,即该点跟根结点不在一条链上,加上这条链的贡献(线段树的区间求和),
再跳到\(top\)的父节点所在链,直到\(top\)为1再加上\(top\)为1这条链的贡献,就能求出1到x的答案了
其实还有另一种不用树剖的做法,用线段树维护前缀和,\(a[x]\)为从\(1\)到\(x\)的点权和,操作1就等于区间修改\(x\)的子树中所有节点,
操作2就等于对\(x\)的子树中每个节点进行一次操作1,这肯定不行,考虑单个节点的贡献,每个节点总共增加的值为它在\(x\)的子树中的深度\(p\)
乘上增加量\(k\),区间贡献和即为区间深度之和乘\(k\).
线段树要多记录区间结点的深度和\(w[p]\),区间修改的式子为\(val[p]+=w[p]*k-(r-l+1)*dep*k\),\(dep\)为\(x\)的父节点的深度
加个lazy标记记录\(dep*k\)就行了
Code 1
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
using namespace std;
typedef long long ll;
const int inf=1e9;
const int maxn=3e5+10;
int n,q;
ll a[maxn];
vector<int>g[maxn];
int top[maxn],in[maxn],out[maxn],sz[maxn],f[maxn],son[maxn],id[maxn],tot;
ll val[maxn<<2],tag[maxn<<2];
void pp(int p){val[p]=val[p<<1]+val[p<<1|1];}
void pd(int l,int r,int p,ll k){val[p]+=(r-l+1)*k,tag[p]+=k;}
void bd(int l,int r,int p){
if(l==r) return val[p]=a[id[l]],void();
int mid=l+r>>1;
bd(lson);bd(rson);pp(p);
}
void up(int dl,int dr,int l,int r,int p,ll k){
if(l>=dl&&r<=dr){
val[p]+=(r-l+1)*k;tag[p]+=k;
return;
}int mid=l+r>>1;
pd(lson,tag[p]);pd(rson,tag[p]);tag[p]=0;
if(dl<=mid) up(dl,dr,lson,k);
if(dr>mid) up(dl,dr,rson,k);
pp(p);
}
ll qy(int dl,int dr,int l,int r,int p){
if(l>=dl&&r<=dr) return val[p];
int mid=l+r>>1;ll ret=0;
pd(lson,tag[p]);pd(rson,tag[p]);tag[p]=0;
if(dl<=mid) ret+=qy(dl,dr,lson);
if(dr>mid) ret+=qy(dl,dr,rson);
return ret;
}
void dfs1(int u){
sz[u]=1;
for(int i=0;i<g[u].size();i++){
int x=g[u][i];
if(x==f[u]) continue;
f[x]=u;dfs1(x);
sz[u]+=sz[x];
if(sz[son[u]]<sz[x]) son[u]=x;
}
}
void dfs2(int u,int t){
top[u]=t;in[u]=++tot;id[tot]=u;
if(son[u]) dfs2(son[u],t);
for(int i=0;i<g[u].size();i++){
int x=g[u][i];
if(x==f[u]||x==son[u]) continue;
dfs2(x,x);
}
out[u]=tot;
}
ll cal(int x){
ll res=0;
while(top[x]!=1){
res+=qy(in[top[x]],in[x],1,n,1);
x=f[top[x]];
}
res+=qy(1,in[x],1,n,1);return res;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=1,a,b;i<n;i++){
scanf("%d%d",&a,&b);
g[a].pb(b);g[b].pb(a);
}
dfs1(1);dfs2(1,1);bd(1,n,1);
while(q--){
int op,x;ll a;
scanf("%d%d",&op,&x);
if(op==1){
scanf("%lld",&a);
up(in[x],in[x],1,n,1,a);
}else if(op==2){
scanf("%lld",&a);
up(in[x],out[x],1,n,1,a);
}else{
printf("%lld\n",cal(x));
}
}
return 0;
}
Code 2
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
using namespace std;
typedef long long ll;
const int inf=1e9;
const int maxn=3e5+10;
int n,q;
int d[maxn];
ll a[maxn],dep[maxn];
vector<int>g[maxn];
int f[maxn],in[maxn],out[maxn],tot;
ll val[maxn<<2],tag[maxn<<2],w[maxn<<2],tw[maxn<<2],qw[maxn<<2];
void pushup(int p){
val[p]=val[p<<1]+val[p<<1|1];
}
void tag1(int l,int r,int p,ll k,ll tk,ll qk){
val[p]+=w[p]*k-(r-l+1)*tk+(r-l+1)*qk;tag[p]+=k;
tw[p]+=tk;qw[p]+=qk;
}
void bd(int l,int r,int p){
if(l==r){
val[p]=a[d[l]];
w[p]=dep[d[l]];
return;
}
int mid=l+r>>1;
bd(lson);bd(rson);
w[p]=w[p<<1]+w[p<<1|1];
pushup(p);
}
void up(int dl,int dr,int l,int r,int p,ll k,ll dep){
if(l>=dl&&r<=dr){
val[p]+=(w[p]-(r-l+1)*dep)*k;tag[p]+=k;
tw[p]+=dep*k;
return;
}int mid=l+r>>1;
tag1(lson,tag[p],tw[p],qw[p]);tag1(rson,tag[p],tw[p],qw[p]);tag[p]=0;tw[p]=0;qw[p]=0;
if(dl<=mid) up(dl,dr,lson,k,dep);
if(dr>mid) up(dl,dr,rson,k,dep);
pushup(p);
}
void upd(int dl,int dr,int l,int r,int p,ll k){
if(l>=dl&&r<=dr){
val[p]+=(r-l+1)*k;qw[p]+=k;
return;
}int mid=l+r>>1;
tag1(lson,tag[p],tw[p],qw[p]);tag1(rson,tag[p],tw[p],qw[p]);tag[p]=0;tw[p]=0;qw[p]=0;
if(dl<=mid) upd(dl,dr,lson,k);
if(dr>mid) upd(dl,dr,rson,k);
pushup(p);
}
ll qy(int dl,int dr,int l,int r,int p){
ll ret=0;
if(l>=dl&&r<=dr) return val[p];int mid=l+r>>1;
tag1(lson,tag[p],tw[p],qw[p]);tag1(rson,tag[p],tw[p],qw[p]);tag[p]=0;tw[p]=0;qw[p]=0;
if(dl<=mid) ret+=qy(dl,dr,lson);
if(dr>mid) ret+=qy(dl,dr,rson);
return ret;
}
void dfs(int u){
in[u]=++tot;d[tot]=u;dep[u]=dep[f[u]]+1;
for(int i=0;i<g[u].size();i++){
int x=g[u][i];
if(x==f[u]) continue;
f[x]=u;a[x]+=a[u];
dfs(x);
}
out[u]=tot;
}
int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
}
for(int i=1,a,b;i<n;i++){
scanf("%d%d",&a,&b);
g[a].pb(b);g[b].pb(a);
}
dfs(1);
bd(1,n,1);
while(q--){
int op,x;
ll a;
scanf("%d%d",&op,&x);
if(op!=3) scanf("%lld",&a);
if(op==1) upd(in[x],out[x],1,n,1,a);
else if(op==2) up(in[x],out[x],1,n,1,a,dep[f[x]]);
else printf("%lld\n",qy(in[x],in[x],1,n,1));
}
return 0;
}
BZOJ 4034 [HAOI2015]树上操作 线段树+树剖或dfs的更多相关文章
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- bzoj 4034: [HAOI2015]树上操作 (树剖+线段树 子树操作)
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 6779 Solved: 2275[Submit][Stat ...
- bzoj 4034: [HAOI2015]树上操作 树链剖分+线段树
4034: [HAOI2015]树上操作 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 4352 Solved: 1387[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 [HAOI2015]树上操作 入栈出栈序+线段树 / 树剖 维护到根距离和
题目大意 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都 ...
- BZOJ 4034 [HAOI2015]树上操作(欧拉序+线段树)
题意: 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增 ...
- BZOJ 4034: [HAOI2015]树上操作 [欧拉序列 线段树]
题意: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 显然树链剖分可做 ...
- BZOJ 4034[HAOI2015]树上操作(树链剖分)
Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点 ...
- bzoj 4034: [HAOI2015]树上操作——树链剖分
Description 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中 ...
随机推荐
- 使用SQL语句查询Elasticsearch索引数据
Elasticsearch 的官方查询语言是 Query DSL,存在毕竟有存在的道理,存在即合理.SQL 作为一个数据库查询语言,它语法简洁,书写方便而且大部分服务端程序员都清楚了解和熟知它的写法. ...
- 怎样使用 v-bind 绑定 html 标签的属性值?
1. 在 Vue 中可是使用 v-bind 对 html 中的 属性 进行绑定, 如下所示, 我们想给这个 a 标签绑定一个 title 值: <!DOCTYPE html> <ht ...
- C# struct结构知识总结
结构是一种值类型,使用struct关键字定义. 结构可以包含字段.常量.事件.属性.方法.构造函数.索引器.运算符和嵌套类型.但若结构中同时需要上述所有成员,应考虑将结构改为类. 嵌套类型:在类或构造 ...
- 09 Python之IO多路复用
四种常见IO模型 阻塞IO(blocking IO).非阻塞IO(nonblocking IO).IO多路复用(IOmultiplexing).异步IO(asynchronous IO) IO发生时涉 ...
- css————关于margin:0px auto的几个居中问题
前言 margin:0px auto;适用于指定了固定宽度的div与其它元素,比如p,img等,使用 margin:0px auto,居中是大家在做css div定位时的最常用方法,但是据我自己的使用 ...
- openlayers加载天地图过程中遇到跨域问题
// 采用openlayers加载天地图 var layer = new ol.layer.Tile({ source: new ol.source.XYZ({ // crossOrigin: 'An ...
- Dreamweaver CS6 破解安装
安装 双击Dreamweaver.dmg文件,然后Command+N,新建一个Finder,接着将Adobe Dreamweaver CS6拖到新建Finder的应用程序中. 在Finder中应用 ...
- ssh登录缓慢,使用ssh -v登录后,显示在 “pledge: network” 处卡顿:
当登录一台服务器时,每次输入密码之后都要等很久才会得到命令提示符,尝试修改了sshd_config中的UseDNS no,但效果依然不好. ssh -v 192.168.12.43 This is p ...
- pycharm的快捷键以及快捷意义
ctrl+a 全选 ctrl+c 复制(默认复制整行) ctrl+v 粘贴 ctrl+x 剪切(默认复制整行) ctrl+f 搜索 ctrl+z 撤销 ctrl+shift+z 反撤销 ctrl+d ...
- Java 基本的数据类型(8种)
1.Java 基本的数据类型(8种) 整型:byte .short .int .long 浮点型:float .double 字符型:char 布尔型:boolean