C - 未曾设想的道路
解法
对于没有 (0) 操作
可以用线段树维护区间 (k) 大值。当然,你还可以做一个关于 “下标” 和 ”数字“ 的前缀和然后暴枚数字。
对于 (0) 操作时 (l=r)
树套树!
外层维护下标,内层维护数字。因为每次只增加一个数字,所以插入是两个 $log $ 的。查询再套个二分就是三个 (log)。
对于 (100\%) 的数据
借用上文一个比较靠谱的思路,我们尝试在有 (0) 操作的情况下维护区间 (k) 大值。
既然修改那么就涉及懒标记的问题,我们需要维护区间 (k) 大懒标记来维护区间 (k) 大值。为了维护区间 (k) 大懒标记还需要记录当前懒标记。
完了吗?
事实上,我们并不能直接用区间 (k) 大懒标记来更新区间 (k) 大值。因为根据题目中数字的构造方法,懒标记必须是连续的(也即从第一个 (0) 操作开始的累积),而区间 (k) 大值可能并没有添加区间 (k) 大懒标记之前的某些懒标记,这样构造出来的区间 (k) 大值就是不合法的。
所以我们还需要维护当前区间 (k) 大值(也即使用了每一次 (0) 操作的数字中的 (k) 大值)。
再讲一下区间 (k) 大懒标记与当前区间 (k) 大值如何合并(令它们分别为 (a[],b[]))。
先在优先队列中加入 (a_i+b_1),然后每次找到最大值 (a_i+b_j) 就加入 (a_i+b_{j+1})。正确性比较显然,时间复杂度 (mathcal O(klog k))。
总时间复杂度 (mathcal O(nklog n+mklog nlog k))。
同机房的巨巨用分块爆踩本做法,下次一定去看看。
代码
大常数竟是我自己。
#pragma GCC optimize(2)
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
#define print(x,y) write(x),putchar(y)
template <class T> inline T read(const T sample) {
T x=0; int f=1; char s;
while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
return x*f;
}
template <class T> inline void write(const T x) {
if(x<0) return (void) (putchar('-'),write(-x));
if(x>9) write(x/10);
putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
typedef pair <int,int> pii;
const int maxn=1e5+5,inf=1e9;
int n,m,h[maxn],tmp[105],ans[105];
struct node {
int laz,la[105],cur[105],mx[105];
node() {
rep(i,0,100) la[i]=cur[i]=mx[i]=-inf;
}
} t[maxn<<2];
priority_queue <pii> q;
void Merge(int *a,int *b) {
static int c[105],i,j; i=1,j=1;
rep(k,1,100)
if(a[i]>b[j]) c[k]=a[i++];
else c[k]=b[j++];
memcpy(a,c,sizeof c);
}
void pushUp(int o) {
memcpy(t[o].cur,t[o<<1].cur,sizeof t[o<<1].cur),Merge(t[o].cur,t[o<<1|1].cur);
memcpy(t[o].mx,t[o<<1].mx,sizeof t[o<<1].mx),Merge(t[o].mx,t[o<<1|1].mx);
}
void Unite(int *a,int *b) {
static int dep[105];
while(!q.empty()) q.pop();
rep(i,1,100) q.push(make_pair(a[i]+b[1],i)),dep[i]=1;
rep(i,1,100) {
pii t=q.top(); q.pop();
tmp[i]=Max(-inf,t.first);
q.push(make_pair(a[t.second]+b[++dep[t.second]],t.second));
}
}
void pushDown(int o) {
if(t[o].la[1]>-1e8) {
rep(i,1,100) tmp[i]=t[o<<1].laz+t[o].la[i];
Merge(t[o<<1].la,tmp);
rep(i,1,100) tmp[i]=t[o<<1|1].laz+t[o].la[i];
Merge(t[o<<1|1].la,tmp);
t[o<<1].laz+=t[o].laz,t[o<<1|1].laz+=t[o].laz;
Unite(t[o].la,t[o<<1].cur),Merge(t[o<<1].mx,tmp);
Unite(t[o].la,t[o<<1|1].cur),Merge(t[o<<1|1].mx,tmp);
rep(i,1,100) t[o<<1].cur[i]+=t[o].laz,t[o<<1|1].cur[i]+=t[o].laz;
rep(i,1,100) t[o].la[i]=-inf;
t[o].laz=0;
}
}
void build(int o,int l,int r) {
if(l==r) return (void)(t[o].cur[1]=t[o].mx[1]=h[l]);
int mid=l+r>>1;
build(o<<1,l,mid),build(o<<1|1,mid+1,r);
pushUp(o);
}
void Modify(int o,int l,int r,int L,int R,int k) {
if(l>R || r<L) return;
if(l>=L && r<=R) {
t[o].laz+=k,tmp[1]=t[o].laz;
rep(i,1,100) t[o].cur[i]+=k;
rep(i,2,100) tmp[i]=-inf;
Merge(t[o].la,tmp),Merge(t[o].mx,t[o].cur);
return;
}
int mid=l+r>>1;
pushDown(o);
Modify(o<<1,l,mid,L,R,k),Modify(o<<1|1,mid+1,r,L,R,k);
pushUp(o);
}
void Query(int o,int l,int r,int L,int R) {
if(l>R || r<L) return;
if(l>=L && r<=R) return (void)(Merge(ans,t[o].mx));
int mid=l+r>>1;
pushDown(o);
Query(o<<1,l,mid,L,R),Query(o<<1|1,mid+1,r,L,R);
}
int main() {
n=read(9),m=read(9);
rep(i,1,n) h[i]=read(9);
build(1,1,n);
while(m--) {
int op=read(9),l=read(9),r=read(9),x=read(9);
if(!op) Modify(1,1,n,l,r,x);
else {
rep(i,1,100) ans[i]=-inf;
Query(1,1,n,l,r);
int res;
rep(i,1,x) if(ans[i]>-1e8) res=ans[i];
print(res,'
');
}
}
return 0;
}