Subseq
Portal --> broken qwq
Description
给你一个长度为\(n\)的整数序列,要支持以下两个操作:
\((0,i,x)\):将第\(i\)个数改成\(x\)
\((1,l,r,k)\):求出\(k\)个区间,满足这些区间没有公共部分并且都在\([l,r]\)的范围内,求这些区间内的数的和的最大值(区间可以为空,空区间和为\(0\))
数据范围:
对于40%的数据,\(n,m,k<=1000\)
对于100%的数据,\(n,m<=10^5,k<=20\)
Solution
这题。。不难但是。。要写的简洁还是需要好好想一下qwq
丢上来主要是因为这题的重载运算符写得好的话会比直接写不知道简洁到哪里去了
然后还有就是。。这什么沙雕数据范围啊!!!难道100%不包含40%的吗!!!一开始没有仔细看于是乎出现了前四个1000的点RE后面的大点全部过掉的奇怪分数分布。。。
好了言归正传
这题因为这个\(k<=20\)所以可以直接非常暴力地变成查\(k\)次最大值,然后将这个最大值区间去掉,具体的话就是直接整个区间取相反数就好了,最后还原一下就好了
然后40%的数据也问题不大(吧)
然后你需要线段树维护最大值、最小值、左边最大值、左边最小值、右边最大值、右边最小值以及区间和。。。最小值的话是因为。。一旦区间取相反数之后。。最大值和最小值就要对调了
然后快乐封装之后就可以写的很好看啦!
代码大概长这样
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=100010,SEG=N*4,inf=1e9;
struct Data{
int l,r,val;
Data(){}
Data(int l1,int r1,int val1){l=l1; r=r1; val=val1;}
friend Data operator + (Data x,Data y)
{return Data(x.l,y.r,x.val+y.val);}
friend bool operator < (Data x,Data y){return x.val<y.val;}
friend bool operator > (Data x,Data y){return x.val>y.val;}
};
Data Max(Data x,Data y){return x>y?x:y;}
Data Min(Data x,Data y){return x<y?x:y;}
struct Info{
Data l,r,ans;
Data sum;
Info(){}
Info(Data x){l=r=ans=sum=x;}
friend Info operator + (Info lch,Info rch){
Info ret;
ret.sum=lch.sum+rch.sum;
ret.l=Max(lch.l,lch.sum+rch.l);
ret.r=Max(rch.r,lch.r+rch.sum);
ret.ans=Max(Max(lch.ans,rch.ans),lch.r+rch.l);
return ret;
}
}rec[1010];
int a[N];
namespace Seg{/*{{{*/
int ch[SEG][2];
Info mx[SEG],mn[SEG];
int tag[SEG];
int n,tot;
void pushup(int x){
mx[x]=mx[ch[x][0]]+mx[ch[x][1]];
mn[x]=mn[ch[x][0]]+mn[ch[x][1]];
}
void _build(int x,int l,int r){
tag[x]=0;
if (l==r){
mx[x]=Info(Data(l,r,a[l]));
mn[x]=Info(Data(l,r,-a[l]));
return;
}
int mid=l+r>>1;
ch[x][0]=++tot; _build(ch[x][0],l,mid);
ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
pushup(x);
}
void build(int _n){n=_n; tot=1; _build(1,1,n);}
void givetag(int x){
tag[x]^=1;
swap(mx[x],mn[x]);
}
void downtag(int x){
if (ch[x][0]) givetag(ch[x][0]);
if (ch[x][1]) givetag(ch[x][1]);
tag[x]=0;
}
void _update(int x,int l,int r,int lx,int rx){
if (l<=lx&&rx<=r){
givetag(x); return;
}
if (tag[x]) downtag(x);
int mid=lx+rx>>1;
if (l<=mid) _update(ch[x][0],l,r,lx,mid);
if (r>mid) _update(ch[x][1],l,r,mid+1,rx);
pushup(x);
}
void update(int l,int r){_update(1,l,r,1,n);}
void _modify(int x,int d,int lx,int rx,int delta){
if (lx==rx){
mx[x]=Info(Data(lx,rx,delta));
mn[x]=Info(Data(lx,rx,-delta));
return;
}
if (tag[x]) downtag(x);
int mid=lx+rx>>1;
if (d<=mid) _modify(ch[x][0],d,lx,mid,delta);
else _modify(ch[x][1],d,mid+1,rx,delta);
pushup(x);
}
void modify(int d,int delta){_modify(1,d,1,n,delta);}
Info _query(int x,int l,int r,int lx,int rx){
if (l<=lx&&rx<=r) return mx[x];
if (tag[x]) downtag(x);
int mid=lx+rx>>1;
if (r<=mid) return _query(ch[x][0],l,r,lx,mid);
else if (l>mid) return _query(ch[x][1],l,r,mid+1,rx);
else {
return _query(ch[x][0],l,mid,lx,mid)+_query(ch[x][1],mid+1,r,mid+1,rx);
}
}
Info query(int l,int r){return _query(1,l,r,1,n);}
}/*}}}*/
int n,m;
void debug(){
Info tmp;
for (int i=1;i<=n;++i)
tmp=Seg::query(i,i),printf("%d ",tmp.ans.val);
printf("\n");
}
void solve(int l,int r,int k){
int cnt=0,sum=0;
Info tmp;
for (int i=1;i<=k;++i){
tmp=Seg::query(l,r);
if (tmp.ans.val>0){
rec[++cnt]=tmp,sum+=tmp.ans.val;
Seg::update(tmp.ans.l,tmp.ans.r);
//debug();
}
else break;
}
for (int i=1;i<=cnt;++i){
Seg::update(rec[i].ans.l,rec[i].ans.r);
//debug();
}
printf("%d\n",sum);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int op,l,r,x,delta;
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",a+i);
Seg::build(n);
//debug();
scanf("%d",&m);
for (int i=1;i<=m;++i){
scanf("%d",&op);
if (op==0){
scanf("%d%d",&x,&delta);
Seg::modify(x,delta);
}
else{
scanf("%d%d%d",&l,&r,&delta);
solve(l,r,delta);
}
}
}