第一次接触吉老师的线段树,写点东西以后复习用
区间有min操作所以我们对树的操作有点不一样
树的结点保存这几个信息
- 总和 s
- 区间最大值 mx
- 区间次大值 se
- 区间最大值的个数 t
- lazy tag
取min更新 其实有点维护最大值的意思
当修改值 val >= mx 直接 return 不用更新
val <= se 的时候 再暴力递归给子结点处理
当 se < val < mx 时候可以打上标记 总值 s -= 最大值变成val的差值(即mx -val) 乘上最大值个数
#include <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <cmath>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
#define ull unsigned long long
#define PI acos(-1)
#define pb(x) push_back(x)
#define il inline
#define re register
#define IO; ios::sync_with_stdio(0);cin.tie(0);
#define ls (o<<1)
#define rs (o<<1|1)
#define pii pair<int,int>
using namespace std;
const int maxn = 1000010;
const int maxm = 400010;
const int INF = 0x3f3f3f3f;
const ll LINF = 3e17+1;
const int mod = 1e9+7;
int n, r, c, m;
inline int read(){
register int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){
x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return (f==1)?x:-x;
}
struct node {
int t,ma,se,tag;ll s;}tr[maxn<<2];
int a[maxn];
void pushup(int o)
{
if (tr[ls].ma == tr[rs].ma)
{
tr[o].ma = tr[ls].ma;
tr[o].t = tr[ls].t + tr[rs].t;
tr[o].se = max(tr[ls].se,tr[rs].se);
}
else if (tr[ls].ma > tr[rs].ma)
{
tr[o].ma = tr[ls].ma, tr[o].t = tr[ls].t;
tr[o].se = max(tr[ls].se,tr[rs].ma);
}
else
{
tr[o].ma = tr[rs].ma, tr[o].t = tr[rs].t;
tr[o].se = max(tr[rs].se,tr[ls].ma);
}
tr[o].s = tr[ls].s + tr[rs].s;
}
void pushdown(int o)
{
int val = tr[o].ma;
if (tr[ls].se < val && val < tr[ls].ma )
{
tr[ls].s -= 1ll*tr[ls].t*(tr[ls].ma - val);
tr[ls].ma = val;tr[ls].tag = 1;
}
if (tr[rs].se < val && val < tr[rs].ma )
{
tr[rs].s -= 1ll*tr[rs].t*(tr[rs].ma - val);
tr[rs].ma = val;tr[rs].tag = 1;
}
tr[o].tag = 0;
}
void build(int o, int l, int r)
{
tr[o].se = -1; tr[o].tag = 0;
if (l == r)
{
tr[o].s = tr[o].ma = a[l];
tr[o].t = 1;
return ;
}
int mid = (l+r)>>1;
build(ls,l,mid);build(rs,mid+1,r);
pushup(o);
}
void modify(int o, int l, int r, int ql, int qr, int val)
{
if (ql <= l && r <= qr)
{
if (val >= tr[o].ma) return ;
if (tr[o].se < val)
{
tr[o].s -= 1ll*tr[o].t*(tr[o].ma-val);
tr[o].ma = val;tr[o].tag = 1;
return ;
}
}
int mid = (l+r)>>1;
if (tr[o].tag) pushdown(o);
if (ql <= mid) modify(ls,l,mid,ql,qr,val);
if (mid < qr) modify(rs,mid+1,r,ql,qr,val);
pushup(o);
}
int querymx(int o, int l, int r, int ql, int qr)
{
if (ql <= l && r <= qr)
{
return tr[o].ma;
}
int mid = (l+r)>>1;
if (tr[o].tag) pushdown(o);
int res = -INF;
if (ql <= mid) res = max(res,querymx(ls,l,mid,ql,qr));
if (mid < qr) res = max(res,querymx(rs,mid+1,r,ql,qr));
return res;
}
ll querysum(int o, int l, int r, int ql, int qr)
{
int mid = (l+r)>>1;
if (ql <= l && r <= qr)
{
return tr[o].s;
}
if (tr[o].tag) pushdown(o);
ll res = 0;
if (ql <= mid) res += querysum(ls,l,mid,ql,qr);
if (mid < qr) res += querysum(rs,mid+1,r,ql,qr);
return res;
}
int main()
{
IO;
int T;
cin >> T;
while (T--)
{
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
build(1,1,n);
for (int op,x,y,t, i = 1; i <= m; i++)
{
cin >> op >> x >> y;
if (op == 0)
{
cin >> t;
modify(1,1,n,x,y,t);
}
else if (op == 1)
{
cout << querymx(1,1,n,x,y) <<endl;
}
else
{
cout << querysum(1,1,n,x,y) << endl;
}
}
}
return 0;
}