题意
数据范围
Analysis
区间取
min
m
i
n
的模板题,于是上吉司机线段树。所谓吉司机线段树,是指复杂度分析基于势能分析乱搞得出,表面暴力实则玄学的可维护区间取
min,max
m
i
n
,
m
a
x
的线段树。
线段树上考虑维护几个值:最大值
mx
m
x
,最大值个数
cnt
c
n
t
,严格次大值
cmx
c
m
x
,区间和
sum
s
u
m
。
其它操作都不是问题,考虑区间取
min
m
i
n
,若对区间
l,r
l
,
r
取
min
m
i
n
一个值
v
v
,分情况讨论:
此时改动并不会影响区间,直接返回。
2.mx>v>cmx
2.
m
x
>
v
>
c
m
x
此时改动仅仅会影响最大值,可以打懒标记解决。
3.v<=cmx
3.
v
<=
c
m
x
此时影响不可打标记解决,考虑暴力做,往子区间递归,重复三个判断。
据势能函数玄学一波时间复杂度分析:
O(nlog2n)
O
(
n
l
o
g
2
n
)
Code
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
const int N = 5e5 + 5;
typedef long long ll;
int ls[N << 2],rs[N << 2];
int mx[N << 2],cx[N << 2],cnt[N << 2],tag[N << 2];
ll sum[N << 2];
int n,m,tot,rt;
inline int read()
{
int x = 0; char ch = getchar();
for (; ch < '0' || ch > '9' ; ch = getchar());
for (; ch >= '0' && ch <= '9' ; ch = getchar()) x = x * 10 + ch - '0';
return x;
}
inline void pushup(int x)
{
sum[x] = sum[ls[x]] + sum[rs[x]];
if (mx[ls[x]] == mx[rs[x]]) mx[x] = mx[ls[x]],cnt[x] = cnt[ls[x]] + cnt[rs[x]],cx[x] = max(cx[ls[x]],cx[rs[x]]);
if (mx[ls[x]] > mx[rs[x]]) mx[x] = mx[ls[x]],cnt[x] = cnt[ls[x]],cx[x] = max(mx[rs[x]],cx[ls[x]]);
if (mx[ls[x]] < mx[rs[x]]) mx[x] = mx[rs[x]],cnt[x] = cnt[rs[x]],cx[x] = max(mx[ls[x]],cx[rs[x]]);
}
inline void down(int x)
{
if (!tag[x]) return;
if (!ls[x]) ls[x] = ++tot; if (!rs[x]) rs[x] = ++tot;
if (mx[ls[x]] > tag[x])
{
sum[ls[x]] -= (ll)cnt[ls[x]] * (mx[ls[x]] - tag[x]),mx[ls[x]] = tag[x];
tag[ls[x]] = tag[x];
}
if (mx[rs[x]] > tag[x])
{
sum[rs[x]] -= (ll)cnt[rs[x]] * (mx[rs[x]] - tag[x]),mx[rs[x]] = tag[x];
tag[rs[x]] = tag[x];
}
tag[x] = 0;
}
void build(int &x,int l,int r)
{
x = ++tot;
if (l == r) { sum[x] = mx[x] = read(),cnt[x] = 1; return; }
int mid = (l + r) >> 1;
build(ls[x],l,mid);
build(rs[x],mid + 1,r);
pushup(x);
}
void exchange(int x,int l,int r,int l1,int r1,int v)
{
if (l > r1 || r < l1 || v >= mx[x]) return;
down(x);
if (v > cx[x] && l >= l1 && r <= r1) { sum[x] -= (ll)cnt[x] * (mx[x] - v),tag[x] = mx[x] = v; return; }
int mid = (l + r) >> 1;
exchange(ls[x],l,mid,l1,r1,v);
exchange(rs[x],mid + 1,r,l1,r1,v);
pushup(x);
}
void change(int x,int l,int r,int pos,int v)
{
down(x);
if (l == r) { mx[x] = sum[x] = max(mx[x] - v,0); return; }
int mid = (l + r) >> 1;
if (pos <= mid) change(ls[x],l,mid,pos,v);
else change(rs[x],mid + 1,r,pos,v);
pushup(x);
}
ll qry(int x,int l,int r,int l1,int r1)
{
down(x);
if (l >= l1 && r <= r1) return sum[x];
int mid = (l + r) >> 1; ll ret = 0;
if (l1 <= mid) ret = qry(ls[x],l,mid,l1,r1);
if (r1 > mid) ret += qry(rs[x],mid + 1,r,l1,r1);
return ret;
}
int main()
{
freopen("dream.in","r",stdin);
freopen("dream.out","w",stdout);
n = read(),m = read();
build(rt,1,n);
ll ans = 0;
while (m--)
{
int opt = read();
if (opt == 1)
{
int pos = read() ^ ans,x = read() ^ ans;
change(rt,1,n,pos,x);
}else if (opt == 2)
{
int l = read() ^ ans,r = read() ^ ans,x = read() ^ ans;
exchange(rt,1,n,l,r,x);
}else
{
int l = read() ^ ans,r = read() ^ ans;
ans = qry(rt,1,n,l,r);
printf("%lld\n",ans);
}
}
fclose(stdin);
fclose(stdout);
return 0;
}