「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{abr1+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(lposbl) ,有一个很显然的结论就是它的答案为序列 { 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'; 
		}
	}
} 
posted @ 2022-10-10 20:18  缙云山车神  阅读(52)  评论(0编辑  收藏  举报