índice
Intervalo máximo
A operação máxima do intervalo geralmente usa os seguintes métodos
Manutenção da árvore do segmento de linha:
- Intervalo máximo mx mxm x
- Estritamente segundo maior intervalo smx smxs m x
- Soma da soma do intervalos u m
- Número máximo de intervalo cnt cntc n t
- Intervalo valor mais preguiçoso marcador preguiçoso preguiçosol a z y
Para atingir a operação de intervalo mínimo, considere o intervalo mantido pelo nó u e proceda da seguinte forma
- 当mx ≤ x mx \ leq xm x≤x . Obviamente, esta modificação não afetará o intervalo mantido por este nó, então saia diretamente.
- 当smx <x <mx smx <x <mxs m x<x<m x , obviamente esta modificação afetará apenas todos os valores máximos neste intervalo, então você pode atualizar diretamente o intervalo e o valor máximo do intervalo de acordo com o número de valores máximos, marcar a marca preguiçosa e sair.
- 当x <= smx x <= smxx<=s m x não pode ser atualizado diretamente, portanto, as subárvores esquerda e direita são recursivamente.
Para a complexidade do tempo, consulte diretamente o Documento da Equipe Nacional de Treinamento de 2016 do Professor Ji (não muito bom ~
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0)
#pragma GCC optimize(2)
#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<random>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=998244353;
const int N=1000010;
// 快读
template <class T>
inline void read(T &res)
{
res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
if (bo) res = ~res + 1;
}
struct node
{
int l,r;
ll mx,smx,sum;
int cnt;
ll lazy;
}tree[N<<2];
int n,m;
ll a[N];
void pushup(int u)
{
tree[u].sum=tree[u<<1].sum+tree[u<<1|1].sum;
if(tree[u<<1].mx>tree[u<<1|1].mx)
{
tree[u].mx=tree[u<<1].mx;
tree[u].smx=max(tree[u<<1].smx,tree[u<<1|1].mx);
tree[u].cnt=tree[u<<1].cnt;
}
else if(tree[u<<1].mx<tree[u<<1|1].mx)
{
tree[u].mx=tree[u<<1|1].mx;
tree[u].smx=max(tree[u<<1|1].smx,tree[u<<1].mx);
tree[u].cnt=tree[u<<1|1].cnt;
}
else
{
tree[u].mx=tree[u<<1|1].mx;
tree[u].smx=max(tree[u<<1].smx,tree[u<<1|1].smx);
tree[u].cnt=tree[u<<1].cnt+tree[u<<1|1].cnt;
}
}
void pushlazy(int u,ll x)
{
if(tree[u].mx<=x) return;
tree[u].sum+=(x-tree[u].mx)*tree[u].cnt;
tree[u].mx=tree[u].lazy=x;
}
void pushdown(int u)
{
if(tree[u].lazy==-1) return;
pushlazy(u<<1,tree[u].lazy),pushlazy(u<<1|1,tree[u].lazy);
tree[u].lazy=-1;
}
void build(int u,int l,int r)
{
tree[u]={
l,r,0,-1,0,0,-1};
if(l==r)
{
tree[u].mx=tree[u].sum=a[l];
tree[u].cnt=1;
return;
}
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
void modify(int u,int l,int r,ll x)
{
if(x>=tree[u].mx) return;
if(tree[u].l>=l&&tree[u].r<=r&&tree[u].smx<x)
{
pushlazy(u,x);
return;
}
pushdown(u);
int mid=tree[u].l+tree[u].r>>1;
if(l<=mid) modify(u<<1,l,r,x);
if(r>mid) modify(u<<1|1,l,r,x);
pushup(u);
}
ll qmax(int u,int l,int r)
{
if(tree[u].l>=l&&tree[u].r<=r) return tree[u].mx;
int mid=tree[u].r+tree[u].l>>1;
pushdown(u);
ll v=-1;
if(l<=mid) v=max(v,qmax(u<<1,l,r));
if(r>mid) v=max(v,qmax(u<<1|1,l,r));
pushup(u);
return v;
}
ll qsum(int u,int l,int r)
{
if(tree[u].l>=l&&tree[u].r<=r) return tree[u].sum;
int mid=tree[u].r+tree[u].l>>1;
pushdown(u);
ll v=0;
if(l<=mid) v+=qsum(u<<1,l,r);
if(r>mid) v+=qsum(u<<1|1,l,r);
pushup(u);
return v;
}
int main()
{
//IO;
int T=1;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
build(1,1,n);
while(m--)
{
int op,l,r;
scanf("%d%d%d",&op,&l,&r);
if(op==0)
{
ll v;
scanf("%lld",&v);
modify(1,l,r,v);
}
else if(op==1)
printf("%lld\n",qmax(1,l,r));
else
printf("%lld\n",qsum(1,l,r));
}
}
return 0;
}