codevs4927 线段树练习5(线段树)
来源:互联网 发布:阿里云网站官方网站 编辑:程序博客网 时间:2024/06/08 01:25
题目
描述
有n个数和5种操作
add a b c:把区间[a,b]内的所有数都增加c
set a b c:把区间[a,b]内的所有数都设为c
sum a b:查询区间[a,b]的区间和
max a b:查询区间[a,b]的最大值
min a b:查询区间[a,b]的最小值
输入
第一行两个整数n,m,第二行n个整数表示这n个数的初始值
接下来m行操作,同题目描述
输出
对于所有的sum、max、min询问,一行输出一个答案
样例输入
10 63 9 2 8 1 7 5 0 4 6add 4 9 4set 2 6 2add 3 8 2sum 2 10max 1 7min 3 6
样例输出
49114
数据范围及提示
10%:
30%:
100%:
保证中间结果在long long(C/C++)、int64(pascal)范围内
解题思路
线段树中每个节点有两个标记:set和add,分别表示重置和区间加。定义一个节点同时存在两个标记时,先下放set标记,再下放加标记,那么当我们进行重置操作时,只需要将当前节点的加标记清零即可。
Code
#include<cstdio>#include<algorithm>#define lid id<<1#define rid id<<1|1#define mid ((tr[id].l+tr[id].r)>>1)#define len(id) (tr[id].r-tr[id].l+1)using namespace std;typedef long long LL;const LL INF = 1e17;const int N = 100005;int n, m, ql, qr;LL a[N], x;char opt[4];struct seg_tree{ int l, r; LL sum, mx, mn; LL set, add; void init(){ l = r = 0; sum = 0, mx = -INF, mn = INF; add = 0, set = INF; }}tr[N<<2];inline void pushup(int id){ tr[id].sum = tr[lid].sum + tr[rid].sum; tr[id].mx = max(tr[lid].mx, tr[rid].mx); tr[id].mn = min(tr[lid].mn, tr[rid].mn);}inline void pushdown(int id){ if(tr[id].l == tr[id].r) return; if(tr[id].set != INF){ LL t = tr[id].set; tr[lid].set = t; tr[lid].add = 0; tr[lid].sum = t * len(lid); tr[lid].mx = tr[lid].mn = t; tr[rid].set = t; tr[rid].add = 0; tr[rid].sum = t * len(rid); tr[rid].mx = tr[rid].mn = t; tr[id].set = INF; } if(tr[id].add){ LL t = tr[id].add; tr[lid].add += t; tr[lid].sum += t * len(lid); tr[lid].mx += t; tr[lid].mn += t; tr[rid].add += t; tr[rid].sum += t * len(rid); tr[rid].mx += t; tr[rid].mn += t; tr[id].add = 0; }}void build(int id, int l, int r){ tr[id].init(); tr[id].l = l, tr[id].r = r; if(tr[id].l == tr[id].r){ tr[id].sum = tr[id].mx = tr[id].mn = a[l]; return; } build(lid, l, mid); build(rid, mid+1, r); pushup(id);}void modify(int id, int l, int r, LL val, int kind){ pushdown(id); if(tr[id].l == l && tr[id].r == r){ if(kind == 0){ tr[id].add += val; tr[id].sum += val * len(id); tr[id].mx += val, tr[id].mn += val; } else{ tr[id].set = val; tr[id].add = 0; tr[id].sum = val * len(id); tr[id].mx = tr[id].mn = val; } return; } if(r <= mid) modify(lid, l, r, val, kind); else if(l > mid) modify(rid, l, r, val, kind); else modify(lid, l, mid, val, kind), modify(rid, mid+1, r, val, kind); pushup(id);}LL query(int id, int l, int r, int kind){ pushdown(id); if(tr[id].l == l && tr[id].r == r){ if(kind == 0) return tr[id].sum; if(kind == 1) return tr[id].mx; if(kind == 2) return tr[id].mn; } if(r <= mid) return query(lid, l, r, kind); else if(l > mid) return query(rid, l, r, kind); else{ if(kind == 0) return query(lid, l, mid, kind) + query(rid, mid+1, r, kind); if(kind == 1) return max(query(lid, l, mid, kind), query(rid, mid+1, r, kind)); if(kind == 2) return min(query(lid, l, mid, kind), query(rid, mid+1, r, kind)); }}int main(){ scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) scanf("%lld", &a[i]); build(1, 1, n); while(m--){ scanf("%s%d%d", opt, &ql, &qr); if(opt[0] == 'a'){ scanf("%lld", &x); modify(1, ql, qr, x, 0); } else if(opt[1] == 'e'){ scanf("%lld", &x); modify(1, ql, qr, x, 1); } else if(opt[0] == 's') printf("%lld\n", query(1, ql, qr, 0)); else if(opt[1] == 'a') printf("%lld\n", query(1, ql, qr, 1)); else if(opt[1] == 'i') printf("%lld\n", query(1, ql, qr, 2)); } return 0;}
阅读全文
0 0
- codevs4927 线段树练习5(线段树)
- 多标记线段树处理法(洛谷3373,codevs4927)
- 线段树练习5
- 线段树练习5
- codevs1080线段树练习(线段树)
- codevs_4927 线段树练习5
- 4927 线段树练习5
- 线段树练习(1)
- 线段树练习
- Wikioi1080线段树练习
- 线段树练习
- 【wikioi1080】 线段树练习
- 线段树练习
- 线段树练习
- 线段树练习 2
- 线段树1练习
- 线段树2练习
- 线段树练习3
- JQuery 链式编程
- java数据库操作(增删改查CRUD)
- 拦截器
- 魔法森林
- 搜索添加历史记录和商品详情
- codevs4927 线段树练习5(线段树)
- python数据预处理之将类别数据转换为数值的方法
- MyShopping 仿京东购物车
- spring中的aop事物
- Leetcode 86. Partition List
- 网络编程(1)
- 计算机网络笔记
- 人脸识别(一)调用face++实现人脸检测。
- C++对象向上转型