「PKUSC2021」逛街【数据结构】
「PKUSC2021」逛街
链接是校内的oj,应该打不开
维护一个序列 b i b_i bi ,表示在若干次操作 1 1 1 后,新序列的第 i i i 个元素为 max { a i , a i + 1 , . . . , a b i } \max\{a_i,a_{i+1},...,a_{b_i}\} max{ai,ai+1,...,abi} 。每一次操作 1 1 1 后,不难发现我们对 b i b_i bi 序列进行了如下的修改。
- 将第 r r r 个元素的一个拷贝放置在原先序列的第 r + 1 r + 1 r+1 个位置。
- 删除原先序列的第 l l l 个位置。
序列 b i b_i bi 可以直接用平衡树维护。
考虑求答案,答案就是序列 { max { a l , . . . , a b l } , max { a l + 1 , . . . , a b l + 1 , } , . . . , max { a r , . . . , a b r } } \{\max\{a_l,...,a_{b_l}\},\max\{a_{l+1},...,a_{b_{l+1}},\},...,\max\{a_{r},...,a_{b_{r}}\}\} {max{al,...,abl},max{al+1,...,abl+1,},...,max{ar,...,abr}} 所有前缀最大值的和。这个就等价于序列 { max { a l , . . . , a b l } , max { a b l + 1 , . . . , a b l + 1 , } , . . . , max { a b r − 1 + 1 , . . . , a b r } } \{\max\{a_l,...,a_{b_l}\},\max\{a_{b_{l}+1},...,a_{b_{l+1}},\},...,\max\{a_{b_{r-1}+1},...,a_{b_{r}}\}\} {max{al,...,abl},max{abl+1,...,abl+1,},...,max{abr−1+1,...,abr}} 的答案(这个序列就是把原序列分成了若干区间,其值为各个区间的最大值元素)。
那么我们每次修改,删除位置 l l l ,相当于合并了两个区间,又由于我们维护的是区间最大值,所以合并两个区间就是删除了其中一个元素(删除的元素将不再对答案产生贡献)。拷贝的元素就没什么用。
设我们现在要求 { max { a l , . . . , a b l } , max { a l + 1 , . . . , a b l + 1 , } , . . . , max { a r , . . . , a b r } } \{\max\{a_l,...,a_{b_l}\},\max\{a_{l+1},...,a_{b_{l+1}},\},...,\max\{a_{r},...,a_{b_{r}}\}\} {max{al,...,abl},max{al+1,...,abl+1,},...,max{ar,...,abr}} 的所有前缀最大值的和,设取到 max { a l , . . . , a b l } \max\{a_l,...,a_{b_l}\} max{al,...,abl} 的元素为 a p o s ( l ≤ p o s ≤ b l ) a_{pos}(l \le pos\le b_l) apos(l≤pos≤bl) ,有一个很显然的结论就是它的答案为序列 { a p o s , a p o s + 1 , . . . , a b r } \{a_{pos},a_{pos+1},...,a_{b_r} \} {apos,apos+1,...,abr} 的所有前缀最大值减去被删除了的元素的贡献。(如果 a p o s a_{pos} apos 也被删了再单独算 a p o s a_{pos} apos 的贡献)。
以上信息都可以用线段树来维护,序列 b i b_i bi 用平衡树来维护,不需要用官方题解上一个 log 的奇奇怪怪的数据结构了,这个做法的复杂度也是 O ( ( n + Q ) log n ) O((n+Q)\log n) O((n+Q)logn) 的。
#include <bits/stdc++.h>
#define N 300005
using namespace std;
typedef long long ll;
inline int read(){
int s=0;
char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s;
}
int n,Q,a[N];
int rand(int mod){ return 1ll*rand()*rand()%mod+1; }
struct treap{
int siz[N<<1],data[N<<1],ls[N<<1],rs[N<<1],root,cnt;
void push_up(int rt){ if(rt) siz[rt]=siz[ls[rt]]+siz[rs[rt]]+1; }
void split(int rt,int num,int &x,int &y){
if(!rt){ x=0,y=0; return; }
if(!num){ x=0,y=rt; return; }
if(siz[ls[rt]]>=num) split(ls[rt],num,x,ls[rt]),y=rt;
else split(rs[rt],num-siz[ls[rt]]-1,rs[rt],y),x=rt;
push_up(x),push_up(y);
}
int merge(int x,int y){
if(!x||!y) return x|y;
int m=rand(siz[x]+siz[y]);
if(m<=siz[x]){ rs[x]=merge(rs[x],y); push_up(x); return x; }
else { ls[y]=merge(x,ls[y]); push_up(y); return y; }
}
void insert(int pos,int c){
int x,y; split(root,pos-1,x,y);
data[++cnt]=c,siz[cnt]=1;
root=merge(merge(x,cnt),y);
}
void del(int pos){
int x,y,z; split(root,pos,x,y); split(x,pos-1,x,z);
root=merge(x,y);
}
int ask(int pos){
if(!pos) return 0;
int x,y,z,res;
split(root,pos,x,y);
split(x,pos-1,x,z);
res=data[z];
root=merge(merge(x,z),y);
return res;
}
}fhq;
struct Sl_tree{
ll tag[N<<2]; int id[N<<2];
void up_data(int L,int R,ll c,int l=1,int r=n,int rt=1){
if(L<=l&&r<=R){ tag[rt]+=c; return; }
int mid=(l+r)>>1;
if(L<=mid) up_data(L,R,c,l,mid,rt<<1);
if(mid<R) up_data(L,R,c,mid+1,r,rt<<1|1);
}
ll ask_ans(int pos,int l=1,int r=n,int rt=1){
if(l==r) return tag[rt];
ll res=tag[rt]; int mid=(l+r)>>1;
if(pos<=mid) res+=ask_ans(pos,l,mid,rt<<1);
else res+=ask_ans(pos,mid+1,r,rt<<1|1);
return res;
}
int ask_max(int L,int R,int l=1,int r=n,int rt=1){
if(L<=l&&r<=R) return id[rt];
int res=0,mid=(l+r)>>1;
if(L<=mid) res=ask_max(L,R,l,mid,rt<<1);
if(mid<R){
int now=ask_max(L,R,mid+1,r,rt<<1|1);
if(a[now]>a[res]) res=now;
}
return res;
}
void build(int l=1,int r=n,int rt=1){
if(l==r){ id[rt]=l; return; }
int mid=(l+r)>>1;
build(l,mid,rt<<1),build(mid+1,r,rt<<1|1);
id[rt]=id[rt<<1];
if(a[id[rt]]<a[id[rt<<1|1]]) id[rt]=id[rt<<1|1];
}
}tree;
ll ans[N];
int st[N],lst[N];
bool ali[N];
int main(){
// freopen("out.in","r",stdin);
// freopen("test.out","w",stdout);
srand(20031101);
n=read(),Q=read();
a[1]=read(); fhq.cnt=1,fhq.root=1,fhq.data[1]=1;
for(int i=2;i<=n;i++) a[i]=read(),fhq.insert(i,i);
tree.build();
int now=1; st[1]=n+1,a[n+1]=2e9;
for(int i=n;i>=1;i--){
while(a[i]>a[st[now]]) lst[st[now]]=i+1,now--;
ans[i]=1ll*a[i]+ans[st[now]]; st[++now]=i;
}
while(now) lst[st[now]]=1,now--;
int ty,l,r;
while(Q--){
ty=read(),l=read(),r=read();
if(ty==1){
fhq.insert(r+1,fhq.ask(r));
int x=fhq.ask(l-1)+1,y=fhq.ask(l),id1=0;
if(x<=y) id1=tree.ask_max(x,y);
fhq.del(l);
int xx=y+1,yy=fhq.ask(l),id2=0;
if(xx<=yy) id2=tree.ask_max(xx,yy);
if(id1&&id2&&id1!=id2){
if(a[id1]>a[id2]) ali[id2]=1,tree.up_data(lst[id2],id2,-a[id2]);
else ali[id1]=1,tree.up_data(lst[id1],id1,-a[id1]);
}
}
else{
l=tree.ask_max(l,fhq.ask(l)),r=fhq.ask(r);
int x=tree.ask_max(l,r);
ll res=ans[l]+tree.ask_ans(l)-ans[x]-tree.ask_ans(x);
if(!ali[x]) res+=a[x];
if(ali[l]) res+=a[l];
cout<<res<<'\n';
}
}
}