前提知识
以下是正文
一、区间最值操作
例题一、
本题要求我们实现三个操作
做法一、
对于第二种和第三种操作我们是已经知道如何写了。
问题就在于第一种操作。
考虑第一种操作是取min
因此当我们这个区间内的最大值
1.如果比给定的k来得小 那么我们不需要任何操作
2.如果这个k<最大值 但是k > 第二大的值(以下称为次大值)
那么我们只需要将最大值全部变成k,修改一下区间和即可.
3.如果这个k<最大值 && k < 次大值
那么我们当前这个结点是处理不了的,直接push_down交给儿子结点
Code
#include <iostream>
#include <cstring>
#define lc (p<<1)
#define rc (p<<1|1)
using namespace std;
typedef long long ll;
const int N = 1100000;
struct Node{
int L,R,tag;//这个tag是维护区间最值操作的
ll sum;
int fir_big,sec_big;
int fir_num;
}tree[N*4];
int a[N];
inline void push_up(int);
void build_tree(int l,int r,int p){
//tag的取值是0~2^31-1 因此我们取-1
tree[p].L=l,tree[p].R=r,tree[p].tag=-1;
if(l==r){
tree[p].sum=a[l];
tree[p].fir_big=a[l];
tree[p].sec_big=-1;
tree[p].fir_num=1;
return;
}
int mid = (l+r)>>1;
build_tree(l,mid,lc);
build_tree(mid+1,r,rc);
push_up(p);
}
inline void push_up(int p){
tree[p].sum=tree[lc].sum+tree[rc].sum;
if(tree[lc].fir_big==tree[rc].fir_big){
tree[p].fir_big=tree[lc].fir_big;
tree[p].fir_num=tree[lc].fir_num+tree[rc].fir_num;
tree[p].sec_big=max(tree[lc].sec_big,tree[rc].sec_big);
}else if(tree[lc].fir_big>tree[rc].fir_big){
tree[p].fir_big=tree[lc].fir_big;
tree[p].fir_num=tree[lc].fir_num;
tree[p].sec_big=max(tree[lc].sec_big,tree[rc].fir_big);
}else{
tree[p].fir_big=tree[rc].fir_big;
tree[p].fir_num=tree[rc].fir_num;
tree[p].sec_big=max(tree[rc].sec_big,tree[lc].fir_big);
}
}
inline void update(int p,int cnt_val){
if(cnt_val<tree[p].fir_big){
//最大值全部变成cnt_val
tree[p].sum+=(1ll*cnt_val-tree[p].fir_big)*tree[p].fir_num;
tree[p].fir_big=tree[p].tag=cnt_val;
}
}
inline void push_down(int p){
if(~tree[p].tag){
update(lc,tree[p].tag);
update(rc,tree[p].tag);
tree[p].tag=-1;
}
}
void modify(int p,int l,int r,int cnt_val){
if(tree[p].L>r||tree[p].R<l||tree[p].fir_big<=cnt_val) return;
if(tree[p].L>=l&&tree[p].R<=r&&tree[p].sec_big<cnt_val){
update(p,cnt_val);
return;
}
push_down(p);
modify(lc,l,r,cnt_val);
modify(rc,l,r,cnt_val);
push_up(p);
}
int queryMax(int p,int l,int r){
if(tree[p].L>r||tree[p].R<l) return 0;
if(tree[p].L>=l&&tree[p].R<=r){
return tree[p].fir_big;
}
push_down(p);
return max(queryMax(lc,l,r),queryMax(rc,l,r));
}
ll querySum(int p,int l,int r){
if(tree[p].L>r||tree[p].R<l) return 0;
if(tree[p].L>=l&&tree[p].R<=r){
return tree[p].sum;
}
push_down(p);
return querySum(lc,l,r)+querySum(rc,l,r);
}
#undef lc
#undef rc
int read(){
int x=0; char ch=0;
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48), ch=getchar();
return x;
}
#if 0
这份代码完成三个功能
1.区间最小值操作
2.求区间最大值
3.求区间和
#endif // 0
int main()
{
int t,n,m;
t=read();
while(t--){
n=read();
m=read();
for(int i=1;i<=n;i++){
a[i]=read();
}
build_tree(1,n,1);
for(int i=1;i<=m;i++){
int op,x,y,t;
op=read();
if(op==0){
x=read();
y=read();
t=read();
modify(1,x,y,t);
}else if(op==1){
x=read();
y=read();
printf("%d\n",queryMax(1,x,y));
}else{
x=read();
y=read();
printf("%lld\n",querySum(1,x,y));
}
}
}
return 0;
}
做法二、
2021.9.8复习更新另一个代码;
这份代码和上面那种做法不同点在于,他不是维护一个改变的tag,而是维护一个加法的tag;
按照例题二的思路,我们将值分为三种,最大值、次大值、其他值;
维护两个标记,最大值的加法标记,其他值的加法标记;
#include <iostream>
#include <cstring>
#define lc (p<<1)
#define rc (p<<1|1)
using namespace std;
typedef long long ll;
const int N = 1000010;
struct Node{
int l,r,mx,sec_mx,mx_num;
int mx_tag,other_tag;
ll sum;
}tr[N<<2];
int a[N],t,n,m;
void push_down(int p);
int read()
{
int x=0; char ch=0;
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48), ch=getchar();
return x;
}
void push_up(int p){
tr[p].sum = tr[lc].sum + tr[rc].sum;
if(tr[lc].mx == tr[rc].mx){
tr[p].mx = tr[lc].mx;
tr[p].mx_num = tr[lc].mx_num + tr[rc].mx_num;
tr[p].sec_mx = max(tr[lc].sec_mx,tr[rc].sec_mx);
}else if(tr[lc].mx > tr[rc].mx){
tr[p].mx = tr[lc].mx;
tr[p].mx_num = tr[lc].mx_num;
tr[p].sec_mx = max(tr[lc].sec_mx,tr[rc].mx);
}else{
tr[p].mx = tr[rc].mx;
tr[p].mx_num = tr[rc].mx_num;
tr[p].sec_mx = max(tr[rc].sec_mx,tr[lc].mx);
}
}
void build(int p,int l,int r){
tr[p].l = l,tr[p].r = r;
tr[p].sec_mx = -1;//因为数据范围是从0开始的
tr[p].mx_tag = tr[p].other_tag = 0;
if(l == r){
tr[p].sum = tr[p].mx = a[l];
tr[p].mx_num = 1;
return;
}
int mid = (l+r) >> 1;
build(lc,l,mid);
build(rc,mid+1,r);
push_up(p);
}
//给这个节点的最大值、其他值加上某些数
void node_update_fun(int p,int mxk,int otherk){
tr[p].sum += 1ll*mxk*tr[p].mx_num + 1ll*(tr[p].r-tr[p].l+1-tr[p].mx_num)*otherk;
if(tr[p].sec_mx != -1) tr[p].sec_mx += otherk;
tr[p].mx += mxk;
tr[p].mx_tag += mxk;
tr[p].other_tag += otherk;
}
void range_min_fun(int p,int l,int r,int k){
if(k>=tr[p].mx) return;
if(tr[p].l>=l&&tr[p].r<=r&&tr[p].sec_mx < k){
node_update_fun(p,k-tr[p].mx,0);
return;
}
push_down(p);
int mid = (tr[p].l + tr[p].r) >> 1;
if(r<=mid){
range_min_fun(lc,l,r,k);
}else if(l>mid){
range_min_fun(rc,l,r,k);
}else{
range_min_fun(lc,l,mid,k);
range_min_fun(rc,mid+1,r,k);
}
push_up(p);
}
void push_down(int p){
int mxk = tr[p].mx_tag;
int otherk = tr[p].other_tag;
int mx = max(tr[lc].mx,tr[rc].mx);
//分清楚左右儿子的值到底应该被哪个k所加
node_update_fun(lc,tr[lc].mx==mx?mxk:otherk,otherk);
node_update_fun(rc,tr[rc].mx==mx?mxk:otherk,otherk);
tr[p].mx_tag = tr[p].other_tag = 0;
}
ll query_sum(int p,int l,int r){
if(tr[p].l>=l&&tr[p].r<=r){
return tr[p].sum;
}
push_down(p);
int mid = (tr[p].l+tr[p].r)>>1;
if(r<=mid){
return query_sum(lc,l,r);
}else if(l>mid){
return query_sum(rc,l,r);
}else{
return query_sum(lc,l,mid) +
query_sum(rc,mid+1,r);
}
}
int query_max(int p,int l,int r){
if(tr[p].l>=l&&tr[p].r<=r){
return tr[p].mx;
}
push_down(p);
int mid = (tr[p].l+tr[p].r)>>1;
if(r<=mid){
return query_max(lc,l,r);
}else if(l>mid){
return query_max(rc,l,r);
}else{
return max(query_max(lc,l,mid),
query_max(rc,mid+1,r));
}
}
int main()
{
t=read();
while(t--){
n=read();
m=read();
for(int i=1;i<=n;++i) a[i] =read();
build(1,1,n);
int op,l,r,k;
while(m--){
op=read();
l=read();
r=read();
if(op == 0){
k=read();
range_min_fun(1,l,r,k);
}else if(op == 1){
printf("%d\n",query_max(1,l,r));
}else{
printf("%lld\n",query_sum(1,l,r));
}
}
}
return 0;
}
例题二、
BZOJ4695
这题在上一题的基础之上
- 增加了区间加
- 区间最大值操作
- 求区间最小值
根据上一题区间最小值的操作 我们来仿造区间最大值操作
对于区间最小值操作
我们维护:区间最大值及个数、次大值
那么对于区间最大值操作
我们维护:区间最小值及个数、次小值
那么我们就将数分为了三类:最大值、最小值、其他值
对于题目要求的三种修改操作
- 对于区间加(减),我们直接对这三类数加(减) 即可
- 对于区间最小值操作以及最大值操作
思路与例题一处相同。
此处以区间最大值操作为例
1.如果最大值比给定的k来得小 那么我们不需要任何操作
2.如果这个k<最大值 但是k > 次大值
那么我们只需要将最大值全部变成k,修改一下区间和即可.
3.如果这个k<最大值 && k < 次大值
那么我们当前这个结点是处理不了的,直接push_down交给儿子结点
那么,我们需要维护三个tag
- 最大值tag
- 最小值tag
- 其他值tag
但是这里有个问题,如果一个区间内的数字很少。
比如只有1个或者2个
当只有一个数字的时候 那么最大值是等于最小值的
我们在push_down的时候不要搞错标记
亦或者只有两个数字的时候 有可能发生次大值等于最小值
也有可能发生次小值等于最大值
此时也要注意是哪个标记的作用
还有一个问题,当前节点的最大最小值是从儿子节点取过来的
此处以最大值为例
如果儿子节点不包含最大值
那么我们给它加的标记应该是其他值的标记(代码中的t3)
如果包含了 那么应该加最大值的标记(代码中的t2)
Code
#include <iostream>
#include <cstdio>
#define lc (p<<1)
#define rc (p<<1|1)
using namespace std;
typedef long long ll;
const int N = 550000;
const int INF = 1e9;
struct Node{
int L,R;
ll sum;
//分别是最小值 最大值 其他值的tag
int tag1,tag2,tag3;
//最大值 最小值 次大值 次小值 最大值个数 最小值个数
int fir_max,fir_min,sec_max,sec_min,mx_num,mn_num;
}tree[N<<2];
int a[N];
void push_up(int p){
tree[p].sum=tree[lc].sum+tree[rc].sum;
if(tree[lc].fir_min==tree[rc].fir_min){
tree[p].fir_min=tree[lc].fir_min;
tree[p].mn_num=tree[lc].mn_num+tree[rc].mn_num;
tree[p].sec_min=min(tree[lc].sec_min,tree[rc].sec_min);
}else if(tree[lc].fir_min<tree[rc].fir_min){
tree[p].fir_min=tree[lc].fir_min;
tree[p].mn_num=tree[lc].mn_num;
tree[p].sec_min=min(tree[lc].sec_min,tree[rc].fir_min);
}else{
tree[p].fir_min=tree[rc].fir_min;
tree[p].mn_num=tree[rc].mn_num;
tree[p].sec_min=min(tree[rc].sec_min,tree[lc].fir_min);
}
if(tree[lc].fir_max==tree[rc].fir_max){
tree[p].fir_max=tree[lc].fir_max;
tree[p].mx_num=tree[lc].mx_num+tree[rc].mx_num;
tree[p].sec_max=max(tree[lc].sec_max,tree[rc].sec_max);
}else if(tree[lc].fir_max>tree[rc].fir_max){
tree[p].fir_max=tree[lc].fir_max;
tree[p].mx_num=tree[lc].mx_num;
tree[p].sec_max=max(tree[lc].sec_max,tree[rc].fir_max);
}else{
tree[p].fir_max=tree[rc].fir_max;
tree[p].mx_num=tree[rc].mx_num;
tree[p].sec_max=max(tree[rc].sec_max,tree[lc].fir_max);
}
}
void build(int p,int l,int r){
tree[p].L=l,tree[p].R=r;
tree[p].tag1=tree[p].tag2=tree[p].tag3=0;
if(l==r){
tree[p].fir_max=tree[p].fir_min=tree[p].sum=a[l];
tree[p].sec_max=-INF;
tree[p].sec_min=INF;
tree[p].mx_num=tree[p].mn_num=1;
return;
}
int mid = (l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
push_up(p);
}
//t1,t2,t3分别是最小值 最大值 其他值的tag标记
void update(int p,int t1,int t2,int t3){
//处理sum
if(tree[p].fir_max==tree[p].fir_min){
//如果只有一个值(最大值等于最小值)
//那么将其他值的tag丢掉
if(t1==t3) t1=t2;
else if(t2==t3) t2=t1;
tree[p].sum+=1ll*tree[p].mx_num*t2;
//else t2=t1;
//tree[p].sum+=1ll*t1*tree[p].mn_num;
}
else{
tree[p].sum+=1ll*tree[p].mx_num*t2+1ll*tree[p].mn_num*t1+
(tree[p].R-tree[p].L+1-tree[p].mx_num-tree[p].mn_num)*t3*1ll;
}
//处理次大值
//如果次大值和最小值相等 那么给它加tag1的值
//否则加tag3的值
//处理次小值同理
if(tree[p].sec_max==tree[p].fir_min){
tree[p].sec_max+=t1;
}else if(tree[p].sec_max!=-INF){
tree[p].sec_max+=t3;
}
//处理次小值
if(tree[p].sec_min==tree[p].fir_max){
tree[p].sec_min+=t2;
}else if(tree[p].sec_min!=INF){
tree[p].sec_min+=t3;
}
//处理最大值、最小值、以及tag
tree[p].fir_max+=t2;
tree[p].fir_min+=t1;
tree[p].tag1+=t1;
tree[p].tag2+=t2;
tree[p].tag3+=t3;
}
void push_down(int p){
int mx = max(tree[lc].fir_max,tree[rc].fir_max);
int mn = min(tree[lc].fir_min,tree[rc].fir_min);
int l1,l2,r1,r2;
l1=tree[lc].fir_min==mn?tree[p].tag1:tree[p].tag3;
l2=tree[lc].fir_max==mx?tree[p].tag2:tree[p].tag3;
update(lc,l1,l2,tree[p].tag3);
r1=tree[rc].fir_min==mn?tree[p].tag1:tree[p].tag3;
r2=tree[rc].fir_max==mx?tree[p].tag2:tree[p].tag3;
update(rc,r1,r2,tree[p].tag3);
tree[p].tag1=tree[p].tag2=tree[p].tag3=0;
}
//给一个区间[L,R] 加上一个数x
void fun1(int p,int l,int r,int k){
if(tree[p].L>r||tree[p].R<l) return;
if(tree[p].L>=l&&tree[p].R<=r){
update(p,k,k,k);
return;
}
push_down(p);
fun1(lc,l,r,k);
fun1(rc,l,r,k);
push_up(p);
}
//把一个区间[L,R] 里小于x 的数变成x
void fun2(int p,int l,int r,int k){
if(tree[p].L>r||tree[p].R<l||tree[p].fir_min>=k) return;
if(tree[p].L>=l&&tree[p].R<=r&&tree[p].sec_min>k){
update(p,k-tree[p].fir_min,0,0);
return;
}
push_down(p);
fun2(lc,l,r,k);
fun2(rc,l,r,k);
push_up(p);
}
//把一个区间[L,R] 里大于x 的数变成x
void fun3(int p,int l,int r,int k){
if(tree[p].L>r||tree[p].R<l||tree[p].fir_max<=k) return;
if(tree[p].L>=l&&tree[p].R<=r&&tree[p].sec_max<k){
update(p,0,k-tree[p].fir_max,0);
return;
}
push_down(p);
fun3(lc,l,r,k);
fun3(rc,l,r,k);
push_up(p);
}
//求区间[L,R] 的和
ll fun4(int p,int l,int r){
if(tree[p].L>r||tree[p].R<l) return 0;
if(tree[p].L>=l&&tree[p].R<=r){
return tree[p].sum;
}
push_down(p);
return fun4(lc,l,r)+fun4(rc,l,r);
}
//求区间[L,R] 的最大值
int fun5(int p,int l,int r){
if(tree[p].L>r||tree[p].R<l) return -INF;
if(tree[p].L>=l&&tree[p].R<=r){
return tree[p].fir_max;
}
push_down(p);
return max(fun5(lc,l,r),fun5(rc,l,r));
}
//求区间[L,R] 的最小值
int fun6(int p,int l,int r){
if(tree[p].L>r||tree[p].R<l) return INF;
if(tree[p].L>=l&&tree[p].R<=r){
return tree[p].fir_min;
}
push_down(p);
return min(fun6(lc,l,r),fun6(rc,l,r));
}
#undef lc
#undef rc
int read()
{
int x=0, w=0; char ch=0;
while (!isdigit(ch)) w|=ch=='-', ch=getchar();
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48), ch=getchar();
return w?-x:x;
}
template<class T>
inline void write(T x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');//取出个位
}
int main()
{
int n;
n=read();
for(int i=1;i<=n;i++){
a[i]=read();
}
build(1,1,n);
int m;
m=read();
while(m--){
int op,l,r,k;
op=read();
switch(op){
case 1:
l=read();r=read();k=read();
fun1(1,l,r,k);
break;
case 2:
l=read();r=read();k=read();
fun2(1,l,r,k);
break;
case 3:
l=read();r=read();k=read();
fun3(1,l,r,k);
break;
case 4:
l=read();r=read();
write(fun4(1,l,r));
putchar('\n');
break;
case 5:
l=read();r=read();
write(fun5(1,l,r));
putchar('\n');
break;
case 6:
l=read();r=read();
write(fun6(1,l,r));
putchar('\n');
break;
}
}
return 0;
}
代码二
2021.9.7复习,写了一份新的,我觉得更加适合理解,思路和上面是一致的;
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 5e5+10;
const int INF = 1e9;
#define lc (p<<1)
#define rc (p<<1|1)
struct Node{
int l,r,mx,mn,mx_num,mn_num,sec_mx,sec_mn;
ll sum;
int mx_tag,mn_tag,other_tag;
}tr[N<<2];
int n,m,a[N];
void push_down(int p);
void push_up(int p){
Node &left = tr[lc],&right = tr[rc],&root = tr[p];
root.sum = left.sum + right.sum;
//操作最大值、次大值
if(left.mx == right.mx){
root.mx = left.mx;
root.mx_num = left.mx_num + right.mx_num;
root.sec_mx = max(left.sec_mx,right.sec_mx);
}else if(left.mx > right.mx){
root.mx = left.mx;
root.mx_num = left.mx_num;
root.sec_mx = max(left.sec_mx,right.mx);
}else{
root.mx = right.mx;
root.mx_num = right.mx_num;
root.sec_mx = max(right.sec_mx,left.mx);
}
//最小值、次小值
if(left.mn == right.mn){
root.mn = left.mn;
root.mn_num = left.mn_num + right.mn_num;
root.sec_mn = min(left.sec_mn,right.sec_mn);
}else if(left.mn < right.mn){
root.mn = left.mn;
root.mn_num = left.mn_num;
root.sec_mn = min(left.sec_mn,right.mn);
}else{
root.mn = right.mn;
root.mn_num = right.mn_num;
root.sec_mn = min(right.sec_mn,left.mn);
}
}
//这个方法对某个节点的最大值、最小值、其他值加上某些数
void node_update_fun(int p,int mnk,int mxk,int otherk){
Node & root = tr[p];
if(root.mx == root.mn){
//不应该被其他值的标签所影响,因为这里只有一个值
if(mnk == otherk) mnk = mxk;
else mxk = mnk;
root.sum += 1ll*root.mn_num * mnk;
}else{
root.sum += 1ll*root.mn_num * mnk + 1ll*root.mx_num * mxk
+ 1ll*(root.r-root.l+1-root.mn_num-root.mx_num)*otherk;
}
//操作次值
if(root.mx == root.sec_mn){
root.sec_mn += mxk;
}else if(root.sec_mn != INF){
root.sec_mn += otherk;
}
if(root.mn == root.sec_mx){
root.sec_mx += mnk;
}else if(root.sec_mx != -INF){
root.sec_mx +=otherk;
}
root.mx += mxk;
root.mn += mnk;
root.mx_tag += mxk;
root.mn_tag += mnk;
root.other_tag += otherk;
}
void range_max_fun(int p,int l,int r,int k){
Node &root = tr[p];
if(root.mn >= k) return;
if(root.l>=l&&root.r<=r&&root.sec_mn > k){
node_update_fun(p,k-root.mn,0,0);
return;
}
push_down(p);
int mid = (root.l + root.r) >> 1;
if(r<=mid){
range_max_fun(lc,l,r,k);
}else if(l>mid){
range_max_fun(rc,l,r,k);
}else{
range_max_fun(lc,l,mid,k);
range_max_fun(rc,mid+1,r,k);
}
push_up(p);
}
void range_min_fun(int p,int l,int r,int k){
Node &root = tr[p];
if(root.mx <= k) return;
if(root.l>=l&&root.r<=r&&root.sec_mx<k){
node_update_fun(p,0,k-root.mx,0);
return;
}
push_down(p);
int mid = (root.l + root.r) >> 1;
if(r<=mid){
range_min_fun(lc,l,r,k);
}else if(l>mid){
range_min_fun(rc,l,r,k);
}else{
range_min_fun(lc,l,mid,k);
range_min_fun(rc,mid+1,r,k);
}
push_up(p);
}
void range_add_fun(int p,int l,int r,int k){
Node & root = tr[p];
if(root.l>=l&&root.r<=r){
node_update_fun(p,k,k,k);
return;
}
push_down(p);
int mid = (root.l + root.r) >> 1;
if(r<=mid){
range_add_fun(lc,l,r,k);
}else if(l>mid){
range_add_fun(rc,l,r,k);
}else{
range_add_fun(lc,l,mid,k);
range_add_fun(rc,mid+1,r,k);
}
push_up(p);
}
ll query_sum(int p,int l,int r){
Node & root = tr[p];
if(root.l>=l&&root.r<=r){
return root.sum;
}
push_down(p);
int mid = (root.l + root.r) >> 1;
if(r<=mid){
return query_sum(lc,l,r);
}else if(l>mid){
return query_sum(rc,l,r);
}else{
return query_sum(lc,l,mid)+
query_sum(rc,mid+1,r);
}
}
int query_max(int p,int l,int r){
Node & root = tr[p];
if(root.l>=l&&root.r<=r){
return root.mx;
}
push_down(p);
int mid = (root.l + root.r) >> 1;
if(r<=mid){
return query_max(lc,l,r);
}else if(l>mid){
return query_max(rc,l,r);
}else{
return max(query_max(lc,l,mid),
query_max(rc,mid+1,r));
}
}
int query_min(int p,int l,int r){
Node & root = tr[p];
if(root.l>=l&&root.r<=r){
return root.mn;
}
push_down(p);
int mid = (root.l + root.r) >> 1;
if(r<=mid){
return query_min(lc,l,r);
}else if(l>mid){
return query_min(rc,l,r);
}else{
return min(query_min(lc,l,mid),
query_min(rc,mid+1,r));
}
}
void push_down(int p){
int mx = max(tr[lc].mx,tr[rc].mx);
int mn = min(tr[lc].mn,tr[rc].mn);
int mxk = tr[p].mx_tag,mnk = tr[p].mn_tag,otherk=tr[p].other_tag;
node_update_fun(lc,tr[lc].mn==mn?mnk:otherk,
tr[lc].mx==mx?mxk:otherk,
otherk
);
node_update_fun(rc,tr[rc].mn==mn?mnk:otherk,
tr[rc].mx==mx?mxk:otherk,
otherk
);
tr[p].mx_tag = tr[p].mn_tag = tr[p].other_tag = 0;
}
void build(int p,int l,int r){
tr[p].l = l,tr[p].r = r;
tr[p].mn_tag = tr[p].mx_tag = tr[p].other_tag = 0;
tr[p].mx = tr[p].sec_mx = -INF;
tr[p].mn = tr[p].sec_mn = INF;
if(l==r){
tr[p].sum = tr[p].mn = tr[p].mx = a[l];
tr[p].mx_num = tr[p].mn_num = 1;
return;
}
int mid = (l+r) >> 1;
build(lc,l,mid);
build(rc,mid+1,r);
push_up(p);
}
int main()
{
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin >> n;
for(int i=1;i<=n;++i) cin >> a[i];
build(1,1,n);
cin >> m;
int op,l,r,k;
while(m--){
cin >> op >> l >> r;
switch(op){
case 1:
cin >> k;
range_add_fun(1,l,r,k);
break;
case 2:
cin >> k;
range_max_fun(1,l,r,k);
break;
case 3:
cin >> k;
range_min_fun(1,l,r,k);
break;
case 4:
cout << query_sum(1,l,r) <<'\n';
break;
case 5:
cout << query_max(1,l,r) << '\n';
break;
case 6:
cout << query_min(1,l,r) << '\n';
break;
}
}
return 0;
}
例题三、
待完成…