【MX-S7-T3】「SMOI-R2」Monotonic Queue 题解
Themooncake · · 题解
我们注意到,题目给出的这个代码只会在尾部退队的时候才会把
但与此同时,我们还会注意到,
但特别的,如果当前枚举的这个
同时,我们还会发现,如果我要退掉单调栈中的数
因此,我们需要维护单调栈内每一个元素的权值
Code
#include<bits/stdc++.h>
/*
注意到 sum 只有在尾部退队的时候才会被 + 到
我们尝试模拟一下这个过程
如果没有这个 l 就是在从左往右做单调栈过程中模拟一遍记录历史最大值就好了
但是有了 l 我们可以通过 l 来控制 一些位置不被加到
所以相当于 找到单调栈中最底部的位置 选择一个到栈顶的连续区段来 +
然后正常单调栈删除末尾
但是 要删除一个数 在这个数上方的数都一定被删了 所以要动态的把这些数的贡献弄进答案里
如果一个数都退不掉 那么我们同时记录一个 lasans 来表示上一次操作的答案 继承它即可
因此我们需要一个数据结构实现以下操作:
1.区间加 2.二分 3.区间覆盖 4.单点插入
显然线段树
*/
using LL=long long;
LL read()
{
char ch=getchar();
LL x=0;
int f=0;
while(ch<'0'||ch>'9')
f=ch=='-',ch=getchar();
while(ch>='0'&&ch<='9')
x=(x<<3)+(x<<1)+(ch&15),ch=getchar();
return f?~x+1:x;
}
const int N=5e5+5;
const LL inf=1e18;
int n,a[N];
LL c[N];
struct node{
int mnA,clr;
LL val,plus;
void add(LL x)
{
val+=x;
plus+=x;
}
void clear()
{
clr=1;
plus=val=mnA=0;
}
};
#define lson rt<<1
#define rson rt<<1|1
node tree[N<<2];
void pushdown(int rt)
{
if(tree[rt].clr)
{
tree[lson].clear();
tree[rson].clear();
tree[rt].clr=0;
}
if(tree[rt].plus)
{
tree[lson].add(tree[rt].plus);
tree[rson].add(tree[rt].plus);
tree[rt].plus=0;
}
}
void update(int rt)
{
tree[rt].mnA=std::min(tree[lson].mnA,tree[rson].mnA);
tree[rt].val=std::max(tree[lson].val,tree[rson].val);
}
void add(int rt,int l,int r,int L,int R,LL x)
{
if(l>R||r<L)
return;
if(L<=l&&r<=R)
{
tree[rt].add(x);
return;
}
pushdown(rt);
int mid=l+r>>1;
add(lson,l,mid,L,R,x);
add(rson,mid+1,r,L,R,x);
update(rt);
}
void clear(int rt,int l,int r,int L,int R)
{
if(l>R||r<L)
return;
if(L<=l&&r<=R)
{
tree[rt].clear();
return;
}
pushdown(rt);
int mid=l+r>>1;
clear(lson,l,mid,L,R);
clear(rson,mid+1,r,L,R);
update(rt);
}
void insert(int rt,int l,int r,int Tar,int AA,LL V)
{
if(l>Tar||r<Tar)
return;
if(l==r)
{
tree[rt].mnA=AA;
tree[rt].val=V;
return;
}
pushdown(rt);
int mid=l+r>>1;
insert(lson,l,mid,Tar,AA,V);
insert(rson,mid+1,r,Tar,AA,V);
update(rt);
}
int get_Lbound(int rt,int l,int r,int AA)
{
if(tree[rt].mnA>AA)
return -1;
if(l==r)
return l;
int mid=l+r>>1;
pushdown(rt);
if(tree[lson].mnA<=AA)
return get_Lbound(lson,l,mid,AA);
else
return get_Lbound(rson,mid+1,r,AA);
}
LL max(int rt,int l,int r,int L,int R)
{
if(l>R||r<L)
return -inf;
if(L<=l&&r<=R)
return tree[rt].val;
pushdown(rt);
int mid=l+r>>1;
return std::max(max(lson,l,mid,L,R),max(rson,mid+1,r,L,R));
}
int top;
LL lasans,ans=-inf,tmp;
int main()
{
// freopen("queue.in","r",stdin);
// freopen("queue.out","w",stdout);
n=read();
for(int i=1;i<=n;++i)
c[i]=read();
for(int i=1;i<=n;++i)
a[i]=read();
for(int i=1;i<=n;++i)
{
int pos=get_Lbound(1,1,n,a[i]);
if(pos>top)//单调栈内一个也退不掉
++top;
else//最少要吃到一位 不可能清空
{
lasans=max(1,1,n,pos,top);
clear(1,1,n,pos,top);
top=pos;
}
ans=std::max(ans,lasans);
insert(1,1,n,top,a[i],lasans);
add(1,1,n,1,top,c[i]);
}
printf("%lld",ans);
}