4034: [HAOI2015]树上操作

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 6779  Solved: 2275
[Submit][Status][Discuss]

Description

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

Input

第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
 

Output

对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

 

Sample Input

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

Sample Output

6
9
13

HINT

对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。

 
思路:
在dfs的时候,加个mx数组,存下每个节点的子节点坐标在线段树中最大的值,那么对以这个点为根节点的子树进行操作是,也就是操作根节点到根节点坐标最大的子节点这段区间,然后就很容易了
实现代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid ll m = (l + r) >> 1
const ll M = 2e5+;
struct node{
ll to,next;
}e[M];
ll n,m,cnt1,cnt,a[M];
ll sum[M<<],lazy[M<<],son[M],fa[M],head[M],siz[M],top[M],dep[M],tid[M],rk[M],mx[M];
void add(ll u,ll v){
e[++cnt1].to = v;e[cnt1].next = head[u];head[u] = cnt1;
e[++cnt1].to = u;e[cnt1].next = head[v];head[v] = cnt1;
} void dfs1(ll u,ll faz,ll deep){
dep[u] = deep;
fa[u] = faz;
siz[u] = ;
for(ll i = head[u];i;i=e[i].next){
ll v = e[i].to;
if(v != fa[u]){
dfs1(v,u,deep+);
siz[u] += siz[v];
if(son[u] == -||siz[v] > siz[son[u]])
son[u] = v;
}
}
} void dfs2(ll u,ll t){
top[u] = t;
mx[u] = cnt;
tid[u] = cnt;
rk[cnt] = u;
cnt++;
if(son[u] == -) return;
dfs2(son[u],t),mx[u] = max(mx[u],mx[son[u]]);
for(ll i = head[u];i;i = e[i].next){
ll v = e[i].to;
if(v != son[u]&&v != fa[u])
dfs2(v,v),mx[u]=max(mx[u],mx[v]);
}
} void pushup(ll rt){
sum[rt] = sum[rt<<] + sum[rt<<|];
} void pushdown(ll l,ll r,ll rt){
if(lazy[rt]){
mid;
sum[rt<<] += lazy[rt]*(m-l+);
sum[rt<<|] += lazy[rt]*(r - m);
lazy[rt<<] += lazy[rt];
lazy[rt<<|] += lazy[rt];
lazy[rt] = ;
}
} void build(ll l,ll r,ll rt){
lazy[rt] = ;
if(l == r){
sum[rt] = a[rk[l]];
return ;
}
mid;
build(lson);
build(rson);
pushup(rt);
} void update(ll L,ll R,ll c,ll l,ll r,ll rt){
if(L <= l&&R >= r){
sum[rt] += c*(r-l+);
lazy[rt]+=c;
return ;
}
pushdown(l,r,rt);
mid;
if(L <= m) update(L,R,c,lson);
if(R > m) update(L,R,c,rson);
pushup(rt);
} ll query(ll L,ll R,ll l,ll r,ll rt){
if(L <= l&&R >= r){
return sum[rt];
}
pushdown(l,r,rt);
mid;
ll ret = ;
if(L <= m) ret += query(L,R,lson);
if(R > m) ret += query(L,R,rson);
return ret;
} ll ask(ll x,ll y){
ll ans = ;
ll fx = top[x],fy = top[y];
while(fx != fy){
if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy);
ans += query(tid[fx],tid[x],,n,);
x = fa[fx];fx=top[x];
}
if(dep[x] > dep[y]) swap(x,y);
ans += query(tid[x],tid[y],,n,);
return ans;
} int main()
{
ll u,v,x,y,z;
scanf("%lld%lld",&n,&m);
cnt1 = ;cnt = ;
memset(son,-,sizeof(son));
for(ll i = ;i <= n;i ++){
scanf("%lld",&a[i]);
}
for(ll i = ;i < n-;i++){
scanf("%lld%lld",&u,&v);
add(u,v);
}
dfs1(,,);dfs2(,),build(,n,);
while(m--){
scanf("%lld%lld",&x,&y);
if(x==){
scanf("%lld",&z);
update(tid[y],tid[y],z,,n,);
}
else if(x == ){
scanf("%lld",&z);
update(tid[y],mx[y],z,,n,);
}
else{
printf("%lld\n",ask(,y));
}
}
return ;
}

bzoj 4034: [HAOI2015]树上操作 (树剖+线段树 子树操作)的更多相关文章

  1. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  2. 【bzoj4699】树上的最短路(树剖+线段树优化建图)

    题意 给你一棵 $n$ 个点 $n-1$ 条边的树,每条边有一个通过时间.此外有 $m$ 个传送条件 $(x_1,y_1,x_2,y_2,c)$,表示从 $x_1$ 到 $x_2$ 的简单路径上的点可 ...

  3. 【BZOJ5210】最大连通子块和 树剖线段树+动态DP

    [BZOJ5210]最大连通子块和 Description 给出一棵n个点.以1为根的有根树,点有点权.要求支持如下两种操作: M x y:将点x的点权改为y: Q x:求以x为根的子树的最大连通子块 ...

  4. BZOJ_2238_Mst_树剖+线段树

    BZOJ_2238_Mst_树剖+线段树 Description 给出一个N个点M条边的无向带权图,以及Q个询问,每次询问在图中删掉一条边后图的最小生成树.(各询问间独立,每次询问不对之后的询问产生影 ...

  5. BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树

    BZOJ_4551_[Tjoi2016&Heoi2016]树_树剖+线段树 Description 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为 ...

  6. BZOJ_2157_旅游_树剖+线段树

    BZOJ_2157_旅游_树剖+线段树 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但 ...

  7. [CF1007D]Ants[2-SAT+树剖+线段树优化建图]

    题意 我们用路径 \((u, v)\) 表示一棵树上从结点 \(u\) 到结点 \(v\) 的最短路径. 给定一棵由 \(n\) 个结点构成的树.你需要用 \(m\) 种不同的颜色为这棵树的树边染色, ...

  8. POJ3237 Tree(树剖+线段树+lazy标记)

    You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbe ...

  9. LUOGU P1967 货车运输(最大生成树+树剖+线段树)

    传送门 解题思路 货车所走的路径一定是最大生成树上的路径,所以先跑一个最大生成树,之后就是求一条路径上的最小值,用树剖+线段树,注意图可能不连通.将边权下放到点权上,但x,y路径上的lca的答案不能算 ...

  10. [LNOI2014]LCA(树剖+线段树)

    \(\%\%\% Fading\) 此题是他第一道黑题(我的第一道黑题是蒲公英) 一直不敢开,后来发现是差分一下,将询问离线,树剖+线段树维护即可 \(Code\ Below:\) #include ...

随机推荐

  1. W25Q128BV W25Q128FV W25Q128JV 什么区别?

    W25Q128BV  W25Q128FV  W25Q128JV  什么区别?    官网没有找到  BV 的相关信息, 倒是有 FV,FW,JV,JW 信息..2019年1月19日19:09:55 F ...

  2. 20155227《网络对抗》Exp6 信息收集与漏洞扫描

    20155227<网络对抗>Exp6 信息收集与漏洞扫描 实践目标 掌握信息搜集的最基础技能与常用工具的使用方法. 基础问题回答 哪些组织负责DNS,IP的管理. 全球根服务器均由美国政府 ...

  3. 20155318 《网络攻防》 Exp7 网络欺诈防范

    20155318 <网络攻防> Exp7 网络欺诈防范 基础问题 通常在什么场景下容易受到DNS spoof攻击 DNS spoof攻击即执行DNS欺骗攻击,通过使用Ettercap来进行 ...

  4. [Oracle]查看数据是否被移入 DataBuffer 的方法

    查看数据是否被移入 DataBuffer 的方法: 例如:表名为 tabxxx, 用户为U2: SQL> grant dba to u2 identified by u2;SQL> con ...

  5. ScreenToGif 代码分析

    ScreenToGif项目由四个文件夹组成: Files 存放协议文件 GifRecorder 存放gif编码器代码 ScreenToGif 存放主代码 Other 存放Hooktest和Transl ...

  6. zabbix问题之snmp监控端口流量断图

    zabbix之snmp监控端口断图问题 在使用zabbix的snmp方式的监控端口流量时,某一个图总是断断续续的(被监控设备有较大的端口流量),经常会出现几分钟内没有图像的问题. 端口流量断图原因: ...

  7. centos7 lldb 调试netcore应用的内存泄漏和死循环示例(dump文件调试)

    写个demo来玩一玩linux平台下使用lldb加载sos来调试netcore应用. 当然,在真实的产线环境中需要分析的数据和难度远远高于demo所示,所以demo的作用也仅仅只能起到介绍工具的作用. ...

  8. docker之搭建LNMP

    一.部署mysql [root@node03 web]# docker run -itd --name lnmp_mysql -p 3308:3306 -e MYSQL_ROOT_PASSWORD=1 ...

  9. centos6 和centos7 安装git 的区别

    centos6 和centos7 安装git 的区别 centos6安装git yum install curl-devel expat-devel gettext-devel openssl-dev ...

  10. python程序出现No module named '_socket' 解决方法

    首先看一下这个错误,错误显示没有这个_socket这个模块 看一个简单的程序理解这个错误是怎么出现的 这个程序就是像浏览器发起请求发开一个链接然后关闭,一直循环,运行之后产生这个错误,产生这个错误的原 ...