题意:
给出一个数组A,要求维护三个操作:
1.给出l,r,t,对于l <= i <= r,Ai = min(Ai,t)
2.给出l,r,询问max{Ai} (l <= i <= r)
3.给出l,r,询问∑Ai (l <= i <= r)
solution:
考虑使用线段树,每个节点维护所在区间内的最大值fr,严格次大值sc,最大值出现次数ti,区间和sum
对区间取min操作,先在线段树上定位区间,分三类讨论:
1.fr <= t,此时修改对该区间毫无影响,,直接返回
2.sc < t < fr,此时仅最大值受影响,稍作修改,打上标记后返回
3.t <= sc,暴力递归左右子树
3操作这样暴力不会TLE???证明详见吉如一的论文,,实际上总复杂度为O(mlogn),但有常数代价
第一次写的时候sc没有及时清0,,导致多组测试的时候被卡爆了。。
实际上及时清零了也是2995ms。。。GG= =
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 1E6 + 10;
const int T = 4;
typedef long long LL;
const int INF = ~0U>>1;
int n,m,ti[maxn*T],fr[maxn*T],sc[maxn*T],Min[maxn*T],A[maxn];
LL sum[maxn*T];
void maintain(int o)
{
int lc = (o<<1),rc = (o<<1|1);
if (fr[lc] == fr[rc])
{
ti[o] = ti[lc] + ti[rc];
fr[o] = fr[lc]; sc[o] = max(sc[lc],sc[rc]);
}
else if (fr[lc] < fr[rc])
{
ti[o] = ti[rc]; fr[o] = fr[rc];
sc[o] = max(sc[rc],fr[lc]);
}
else
{
ti[o] = ti[lc]; fr[o] = fr[lc];
sc[o] = max(sc[lc],fr[rc]);
}
sum[o] = sum[lc] + sum[rc];
}
void pushdown(int o,int l,int r)
{
if (Min[o] >= fr[o]) {Min[o] = INF; return;}
int lc = (o<<1),rc = (o<<1|1);
if (sc[o] < Min[o])
{
sum[o] += 1LL*ti[o]*(Min[o] - fr[o]);
fr[o] = Min[o];
if (l == r) {Min[o] = INF; return;}
Min[lc] = min(Min[lc],Min[o]);
Min[rc] = min(Min[rc],Min[o]);
Min[o] = INF;
}
else
{
Min[lc] = min(Min[lc],Min[o]);
Min[rc] = min(Min[rc],Min[o]);
Min[o] = INF; int mid = (l + r) >> 1;
pushdown(o<<1,l,mid);
pushdown(o<<1|1,mid+1,r);
maintain(o);
}
}
void Build(int o,int l,int r)
{
if (l == r)
{
sum[o] = fr[o] = A[l]; sc[o] = 0;
ti[o] = 1; Min[o] = INF; return;
}
int mid = (l + r) >> 1; Min[o] = INF;
Build(o<<1,l,mid); Build(o<<1|1,mid+1,r);
maintain(o);
}
void Modify(int o,int l,int r,int ml,int mr,int k)
{
if (ml <= l && r <= mr)
{
Min[o] = min(Min[o],k);
pushdown(o,l,r); return;
}
int mid = (l + r) >> 1; pushdown(o,l,r);
if (ml <= mid) Modify(o<<1,l,mid,ml,mr,k); else pushdown(o<<1,l,mid);
if (mr > mid) Modify(o<<1|1,mid+1,r,ml,mr,k); else pushdown(o<<1|1,mid+1,r);
maintain(o);
}
int Get_Max(int o,int l,int r,int ql,int qr)
{
pushdown(o,l,r);
if (ql <= l && r <= qr) return fr[o];
int mid = (l + r) >> 1,ret = 0;
if (ql <= mid) ret = Get_Max(o<<1,l,mid,ql,qr);
if (qr > mid) ret = max(ret,Get_Max(o<<1|1,mid+1,r,ql,qr));
return ret;
}
LL Get_Sum(int o,int l,int r,int ql,int qr)
{
pushdown(o,l,r);
if (ql <= l && r <= qr) return sum[o];
int mid = (l + r) >> 1; LL ret = 0;
if (ql <= mid) ret = Get_Sum(o<<1,l,mid,ql,qr);
if (qr > mid) ret += Get_Sum(o<<1|1,mid+1,r,ql,qr);
return ret;
}
int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret*10 + ch - '0',ch = getchar();
return ret;
}
char ch[20];
void Print(LL x)
{
if (!x) {puts("0"); return;}
int len = 0;
while (x) ch[++len] = x % 10LL,x /= 10LL;
for (int i = len; i; i--) putchar(ch[i] + '0');
puts("");
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
freopen("test.txt","w",stdout);
#endif
int cas = getint();
while (cas--)
{
n = getint(); m = getint();
for (int i = 1; i <= n; i++) A[i] = getint();
Build(1,1,n);
while (m--)
{
int typ = getint(),l,r;
l = getint(); r = getint();
if (!typ) Modify(1,1,n,l,r,getint());
else if (typ == 1) Print(Get_Max(1,1,n,l,r));
else Print(Get_Sum(1,1,n,l,r));
}
}
return 0;
}