题目描述

给定一个长度为 N 序列,编号从 1 到 N 。要求支持下面几种操作:
1.给一个区间[L,R] 加上一个数x 
2.把一个区间[L,R] 里小于x 的数变成x 
3.把一个区间[L,R] 里大于x 的数变成x 
4.求区间[L,R] 的和
5.求区间[L,R] 的最大值
6.求区间[L,R] 的最小值

输入

第一行一个整数 N 表示序列长度。
第二行 N 个整数 Ai 表示初始序列。
第三行一个整数 M 表示操作个数。
接下来 M 行,每行三或四个整数,第一个整数 Tp 表示操作类型,接下来 L,R,X 或 L,R 表述操作数。
1<=tp<=6,N,M<=5*10^5,|Ai|<=10^8
Tp=1时,|x|<=1000
Tp=2或3时,|x|<=10^8

输出

对于每个4,5,6类型的操作输出一行一个整数表示答案。

样例输入

2
1 2
2
2 1 2 2
4 1 2

样例输出

4


题解

线段树区间最值操作

吉老师的Segment tree Beats! 中的题。

维护区间最小值、最小值个数、严格次小值、最大值、最大值个数、严格次大值、区间和、区间加和标记即可。。。

还要注意,修改区间最小值时要注意其对最大值、严格次大值是否有影响,修改区间最大值时要注意其对最小值、严格次小值的影响。

想想都觉得麻烦。。。

时间复杂度 $O(n\log^2n)$

注意本题略微卡常,不能全用long long,只有区间和使用long long维护。

#include <cstdio>
#include <algorithm>
#define N 2000010
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
using namespace std;
typedef long long ll;
const int inf = 1 << 30;
int mx[N] , cx[N] , sx[N] , mn[N] , cn[N] , sn[N] , add[N];
ll sum[N];
inline void pushup(int x)
{
int ls = x << 1 , rs = x << 1 | 1;
sum[x] = sum[ls] + sum[rs];
if(mx[ls] > mx[rs]) mx[x] = mx[ls] , cx[x] = cx[ls] , sx[x] = max(sx[ls] , mx[rs]);
if(mx[ls] < mx[rs]) mx[x] = mx[rs] , cx[x] = cx[rs] , sx[x] = max(mx[ls] , sx[rs]);
if(mx[ls] == mx[rs]) mx[x] = mx[ls] , cx[x] = cx[ls] + cx[rs] , sx[x] = max(sx[ls] , sx[rs]);
if(mn[ls] < mn[rs]) mn[x] = mn[ls] , cn[x] = cn[ls] , sn[x] = min(sn[ls] , mn[rs]);
if(mn[ls] > mn[rs]) mn[x] = mn[rs] , cn[x] = cn[rs] , sn[x] = min(mn[ls] , sn[rs]);
if(mn[ls] == mn[rs]) mn[x] = mn[ls] , cn[x] = cn[ls] + cn[rs] , sn[x] = min(sn[ls] , sn[rs]);
}
inline void pushdown(int l , int r , int x)
{
int ls = x << 1 , rs = x << 1 | 1;
if(add[x])
{
int mid = (l + r) >> 1;
mx[ls] += add[x] , sx[ls] += add[x] , mn[ls] += add[x] , sn[ls] += add[x] , sum[ls] += (mid - l + 1) * add[x] , add[ls] += add[x];
mx[rs] += add[x] , sx[rs] += add[x] , mn[rs] += add[x] , sn[rs] += add[x] , sum[rs] += (r - mid) * add[x] , add[rs] += add[x];
add[x] = 0;
}
if(mx[ls] > mx[x])
{
if(mn[ls] == mx[ls]) mn[ls] = mx[x];
if(sn[ls] == mx[ls]) sn[ls] = mx[x];
sum[ls] += 1ll * (mx[x] - mx[ls]) * cx[ls] , mx[ls] = mx[x];
}
if(mx[rs] > mx[x])
{
if(mn[rs] == mx[rs]) mn[rs] = mx[x];
if(sn[rs] == mx[rs]) sn[rs] = mx[x];
sum[rs] += 1ll * (mx[x] - mx[rs]) * cx[rs] , mx[rs] = mx[x];
}
if(mn[ls] < mn[x])
{
if(mx[ls] == mn[ls]) mx[ls] = mn[x];
if(sx[ls] == mn[ls]) sx[ls] = mn[x];
sum[ls] += 1ll * (mn[x] - mn[ls]) * cn[ls] , mn[ls] = mn[x];
}
if(mn[rs] < mn[x])
{
if(mx[rs] == mn[rs]) mx[rs] = mn[x];
if(sx[rs] == mn[rs]) sx[rs] = mn[x];
sum[rs] += 1ll * (mn[x] - mn[rs]) * cn[rs] , mn[rs] = mn[x];
}
}
void build(int l , int r , int x)
{
if(l == r)
{
scanf("%lld" , &sum[x]) , mx[x] = mn[x] = sum[x] , cx[x] = cn[x] = 1 , sx[x] = -inf , sn[x] = inf;
return;
}
int mid = (l + r) >> 1;
build(lson) , build(rson);
pushup(x);
}
void vadd(int b , int e , int a , int l , int r , int x)
{
if(b <= l && r <= e)
{
mx[x] += a , sx[x] += a , mn[x] += a , sn[x] += a , sum[x] += 1ll * (r - l + 1) * a , add[x] += a;
return;
}
pushdown(l , r , x);
int mid = (l + r) >> 1;
if(b <= mid) vadd(b , e , a , lson);
if(e > mid) vadd(b , e , a , rson);
pushup(x);
}
void vmax(int b , int e , int a , int l , int r , int x)
{
if(mn[x] >= a) return;
if(b <= l && r <= e && sn[x] > a)
{
if(mx[x] == mn[x]) mx[x] = a;
if(sx[x] == mn[x]) sx[x] = a;
sum[x] += 1ll * (a - mn[x]) * cn[x] , mn[x] = a;
return;
}
pushdown(l , r , x);
int mid = (l + r) >> 1;
if(b <= mid) vmax(b , e , a , lson);
if(e > mid) vmax(b , e , a , rson);
pushup(x);
}
void vmin(int b , int e , int a , int l , int r , int x)
{
if(mx[x] <= a) return;
if(b <= l && r <= e && sx[x] < a)
{
if(mn[x] == mx[x]) mn[x] = a;
if(sn[x] == mx[x]) sn[x] = a;
sum[x] += 1ll * (a - mx[x]) * cx[x] , mx[x] = a;
return;
}
pushdown(l , r , x);
int mid = (l + r) >> 1;
if(b <= mid) vmin(b , e , a , lson);
if(e > mid) vmin(b , e , a , rson);
pushup(x);
}
ll qsum(int b , int e , int l , int r , int x)
{
if(b <= l && r <= e) return sum[x];
pushdown(l , r , x);
int mid = (l + r) >> 1; ll ans = 0;
if(b <= mid) ans += qsum(b , e , lson);
if(e > mid) ans += qsum(b , e , rson);
return ans;
}
int qmax(int b , int e , int l , int r , int x)
{
if(b <= l && r <= e) return mx[x];
pushdown(l , r , x);
int mid = (l + r) >> 1 , ans = -inf;
if(b <= mid) ans = max(ans , qmax(b , e , lson));
if(e > mid) ans = max(ans , qmax(b , e , rson));
return ans;
}
int qmin(int b , int e , int l , int r , int x)
{
if(b <= l && r <= e) return mn[x];
pushdown(l , r , x);
int mid = (l + r) >> 1 , ans = inf;
if(b <= mid) ans = min(ans , qmin(b , e , lson));
if(e > mid) ans = min(ans , qmin(b , e , rson));
return ans;
}
int main()
{
int n , m , opt , x , y , z;
scanf("%d" , &n);
build(1 , n , 1);
scanf("%d" , &m);
while(m -- )
{
scanf("%d%d%d" , &opt , &x , &y);
if(opt == 1) scanf("%d" , &z) , vadd(x , y , z , 1 , n , 1);
if(opt == 2) scanf("%d" , &z) , vmax(x , y , z , 1 , n , 1);
if(opt == 3) scanf("%d" , &z) , vmin(x , y , z , 1 , n , 1);
if(opt == 4) printf("%lld\n" , qsum(x , y , 1 , n , 1));
if(opt == 5) printf("%d\n" , qmax(x , y , 1 , n , 1));
if(opt == 6) printf("%d\n" , qmin(x , y , 1 , n , 1));
}
return 0;
}

【bzoj4695】最假女选手 线段树区间最值操作的更多相关文章

  1. 【bzoj4355】Play with sequence 线段树区间最值操作

    题目描述 维护一个长度为N的序列a,现在有三种操作: 1)给出参数U,V,C,将a[U],a[U+1],...,a[V-1],a[V]都赋值为C. 2)给出参数U,V,C,对于区间[U,V]里的每个数 ...

  2. 【hdu5306】Gorgeous Sequence 线段树区间最值操作

    题目描述 给你一个序列,支持三种操作: $0\ x\ y\ t$ :将 $[x,y]$ 内大于 $t$ 的数变为 $t$ :$1\ x\ y$ :求 $[x,y]$ 内所有数的最大值:$2\ x\ y ...

  3. BZOJ.4695.最假女选手(线段树 Segment tree Beats!)

    题目链接 区间取\(\max,\ \min\)并维护区间和是普通线段树无法处理的. 对于操作二,维护区间最小值\(mn\).最小值个数\(t\).严格次小值\(se\). 当\(mn\geq x\)时 ...

  4. BZOJ 4695 最假女选手 线段树

    题意: 给定一个长度为 N序列,编号从1 到 N.要求支持下面几种操作: 1.给一个区间[L,R] 加上一个数x  2.把一个区间[L,R] 里小于x 的数变成x  3.把一个区间[L,R] 里大于x ...

  5. HDU 5306 Gorgeous Sequence[线段树区间最值操作]

    Gorgeous Sequence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  6. HUD.2795 Billboard ( 线段树 区间最值 单点更新 单点查询 建树技巧)

    HUD.2795 Billboard ( 线段树 区间最值 单点更新 单点查询 建树技巧) 题意分析 题目大意:一个h*w的公告牌,要在其上贴公告. 输入的是1*wi的w值,这些是公告的尺寸. 贴公告 ...

  7. HDU 3911 Black And White(线段树区间合并+lazy操作)

    开始以为是水题,结果...... 给你一些只有两种颜色的石头,0为白色,1为黑色. 然后两个操作: 1 l r 将[ l , r ]内的颜色取反 0 l r 计算[ l , r ]内最长连续黑色石头的 ...

  8. UVA 1400."Ray, Pass me the dishes!" -分治+线段树区间合并(常规操作+维护端点)并输出最优的区间的左右端点-(洛谷 小白逛公园 升级版)

    "Ray, Pass me the dishes!" UVA - 1400 题意就是线段树区间子段最大和,线段树区间合并,但是这道题还要求输出最大和的子段的左右端点.要求字典序最小 ...

  9. cf834D(dp+线段树区间最值,区间更新)

    题目链接: http://codeforces.com/contest/834/problem/D 题意: 每个数字代表一种颜色, 一个区间的美丽度为其中颜色的种数, 给出一个有 n 个元素的数组, ...

随机推荐

  1. C语言复习20170716

    C语言复习20170716 C数据类型 图片来自:C语言基本数据类型简介 C语言程序处理的数据有常量和变量两种形式. 常量是在程序中不能改变其值的量.例如:整型常量.实型常量.字符常量.字符串常量和枚 ...

  2. HBase核心功能模块--读书笔记

    客户端Client 客户端 Client 是整个 HBase 系统的入口.使用者直接通过客户端操作 HBase.客户端 使用 HBase 的 RPC 机制与 HMaster 和 RegionServe ...

  3. FFT&NTT总结

    FFT&NTT总结 一些概念 \(DFT:\)离散傅里叶变换\(\rightarrow O(n^2)\)计算多项式卷积 \(FFT:\)快速傅里叶变换\(\rightarrow O(nlogn ...

  4. linux挂在samba服务器到本地(用于备份文件到nas或者windows的文件服务器)

    1.安装工具 首先在linux上安装samba访问工具 sudo apt-get install smbclient sudo apt-get install cifs-utils 2.查看服务器目录 ...

  5. 天马行空-Ops平台建设概述

    1           概述 什么是Ops平台,Ops平台的目标是什么,建设的考虑点有哪些?本章节以实际生活中医院的例子来进行各形象的阐述. 医院包含各种诊断治疗设备,病历库,医生.一个孕妇需要到医院 ...

  6. win7重装系统后设置Python2.7环境

    起因 台式机的主板莫名出现问题,显示器画面卡顿不能动,鼠标键盘无反应,在这种情况下只好按住电源键断电.下面重启后,显示器无画面,猜测开机后没有进BIOS.然后就拆机箱,拔下电源线后撬起主板电池几秒再放 ...

  7. AppCan 之初体验

    平台概述 什么是AppCan 移步这里,楼主的一句话:可以匹敌 Phonegap .Titanium .Sencha Touch .MUI .ImagApp.Nitrous .apicloud .起步 ...

  8. 关于js中一个对象当做参数传递是按值传递还是按引用传递的个人看法

    在<JavaScript高级程序设计>这本书中有这样一段话:有很多开发人员错误的认为:在局部作用域中修改的对象会在全局作用域中反映出来,就说明参数是按引用传递的.换句话说,尼古拉认为当一个 ...

  9. Arctic Network POJ 2349 (最小生成树思想)

    Description The Department of National Defence (DND) wishes to connect several northern outposts by ...

  10. 404 Note Found 现场编程

    目录 组员职责分工 github 的提交日志截图 程序运行截图 程序运行环境 GUI界面 基础功能实现 运行视频 LCG算法 过滤(降权)算法 算法思路 红黑树 附加功能一 背景 实现 附加功能二(迭 ...