1. 程式人生 > >[BZOJ 4826]影魔 區間修改主席樹 標記永久化

[BZOJ 4826]影魔 區間修改主席樹 標記永久化

brush sca ostream www cpp pad stream i+1 return

為了這道題還特地去學了標記永久化,可能對於區間修改主席樹或者樹套樹比較有用吧OvO

我們可以把答案分為兩部分:p1造成的和p2造成的

我們枚舉序列,用單調棧求出序列每一個位置i,左右邊第一個比它大的L,R

開三棵主席樹tree1 tree2 tree3

把L扔進tree1的R位置(單點+1),L+1~i-1扔進tree2的R位置,i+1~R-1扔進tree3的L位置(區間+1)

然後詢問[l,r]的時候,求出三棵區間主席樹

p1造成的貢獻為區間tree1內大於等於L的個數

p2造成的貢獻為區間tree2內大於等於L的個數和區間tree3內小於等於R的個數

因為要建主席樹,所以我們先拿vector存一下每個位置需要往裏扔什麽,然後再掃一遍到一個點全扔進去(註意以這個點的最後一個版本為此位置的主席樹)

還有要開long long!!!

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define pos(i,a,b) for(int i=(a);i<=(b);i++)
#define pos2(i,a,b) for(int i=(a);i>=(b);i--)
#include<vector>
#define N 301000
#define LL long long
using namespace std;
int n,m,p1,p2;
int a[N];
int stack[N];
struct xixi{
	int l,r;
}cun[N];
vector<int> add1[N];
vector<xixi> add_l[N],add_r[N];
struct haha{
	int lc,rc,sum;
}tree1[N*25],tree_l[N*25],tree_r[N*25];
int size1,size_l,size_r;
int root1[N],root_l[N],root_r[N];
int biao_r[N*25],biao_l[N*25];
void update1(int &rt,int l,int r,int pos){
	tree1[++size1]=tree1[rt];
	int t=size1;tree1[t].sum++;rt=t;
	if(l==r) return;
	int mid=(l+r)>>1;
	if(pos<=mid) update1(tree1[rt].lc,l,mid,pos);
	else update1(tree1[rt].rc,mid+1,r,pos);
	tree1[rt].sum=tree1[tree1[rt].lc].sum+tree1[tree1[rt].rc].sum;
}
void update_r(int old,int &rt,int l,int r,int xl,int xr){
	if(!rt) rt=++size_r;
	if(l>=xl&&r<=xr){
		biao_r[rt]=biao_r[old]+1;
		tree_r[rt].sum=tree_r[old].sum+(r-l+1);
		tree_r[rt].lc=tree_r[old].lc;
		tree_r[rt].rc=tree_r[old].rc;
		return;
	}
	tree_r[rt].sum=tree_r[old].sum+(xr-xl+1);
	int mid=(l+r)>>1;
	if(xr<=mid){
		update_r(tree_r[old].lc,tree_r[rt].lc,l,mid,xl,xr);
		tree_r[rt].rc=tree_r[old].rc;
	}
	else{
		if(xl>mid){
			update_r(tree_r[old].rc,tree_r[rt].rc,mid+1,r,xl,xr);
			tree_r[rt].lc=tree_r[old].lc;
		}
		else{
			update_r(tree_r[old].lc,tree_r[rt].lc,l,mid,xl,mid);
			update_r(tree_r[old].rc,tree_r[rt].rc,mid+1,r,mid+1,xr);
		}
	}
}
void update_l(int old,int &rt,int l,int r,int xl,int xr){
	if(!rt) rt=++size_l;
	if(l>=xl&&r<=xr){
		biao_l[rt]=biao_l[old]+1;
		tree_l[rt].sum=tree_l[old].sum+(r-l+1);
		tree_l[rt].lc=tree_l[old].lc;
		tree_l[rt].rc=tree_l[old].rc;
		return;
	}
	tree_l[rt].sum=tree_l[old].sum+(xr-xl+1);
	int mid=(l+r)>>1;
	if(xr<=mid){
		update_l(tree_l[old].lc,tree_l[rt].lc,l,mid,xl,xr);
		tree_l[rt].rc=tree_l[old].rc;
	}
	else{
		if(xl>mid){
			update_l(tree_l[old].rc,tree_l[rt].rc,mid+1,r,xl,xr);
			tree_l[rt].lc=tree_l[old].lc;
		}
		else{
			update_l(tree_l[old].lc,tree_l[rt].lc,l,mid,xl,mid);
			update_l(tree_l[old].rc,tree_l[rt].rc,mid+1,r,mid+1,xr);
		}
	}
}
int query1(int rtl,int rtr,int l,int r,int pos){
	if(!rtr) return 0;
	if(r<pos) return 0;
	if(l==r) return tree1[rtr].sum-tree1[rtl].sum;
	int mid=(l+r)>>1;
	if(pos<=mid){
		return query1(tree1[rtl].lc,tree1[rtr].lc,l,mid,pos)+tree1[tree1[rtr].rc].sum-tree1[tree1[rtl].rc].sum;	
	} 
	else return query1(tree1[rtl].rc,tree1[rtr].rc,mid+1,r,pos);
}
int query_r(int rtl,int rtr,int ad,int l,int r,int pos){
	 if(r<pos) return 0;
	 int tempad=biao_r[rtr]-biao_r[rtl];
	 if(l==r||l>=pos){
	 	return tree_r[rtr].sum-tree_r[rtl].sum+(ad)*(r-l+1);
	 }	
	 int mid=(l+r)>>1;
	 if(pos<=mid){
	 	return query_r(tree_r[rtl].lc,tree_r[rtr].lc,ad+tempad,l,mid,pos)+query_r(tree_r[rtl].rc,tree_r[rtr].rc,ad+tempad,mid+1,r,pos);
	 }
	 else return query_r(tree_r[rtl].rc,tree_r[rtr].rc,ad+tempad,mid+1,r,pos);
}
int query_l(int rtl,int rtr,int ad,int l,int r,int pos){
	 if(l>pos) return 0;
	 int tempad=biao_l[rtl]-biao_l[rtr];
	 if(l==r||r<=pos){
	 	return tree_l[rtl].sum-tree_l[rtr].sum+(ad)*(r-l+1);
	 }	
	 int mid=(l+r)>>1;
	 if(pos>mid){
	 	return query_l(tree_l[rtl].lc,tree_l[rtr].lc,ad+tempad,l,mid,pos)+query_l(tree_l[rtl].rc,tree_l[rtr].rc,ad+tempad,mid+1,r,pos);
	 }
	 else return query_l(tree_l[rtl].lc,tree_l[rtr].lc,ad+tempad,l,mid,pos);
}
int main(){
	scanf("%d%d%d%d",&n,&m,&p1,&p2);
	pos(i,1,n) scanf("%d",&a[i]);
	stack[0]=1;
	pos(i,1,n){
		while(stack[0]>1&&a[stack[stack[0]-1]]<a[i]) stack[0]--;
		if(stack[0]==1)	cun[i].l=0;
		else cun[i].l=stack[stack[0]-1];
		stack[stack[0]++]=i;
	}
	stack[0]=1;
	pos2(i,n,1){
		while(stack[0]>1&&a[stack[stack[0]-1]]<a[i]) stack[0]--;
		if(stack[0]==1)	cun[i].r=n+1;
		else cun[i].r=stack[stack[0]-1];
		stack[stack[0]++]=i;
	}
	pos(i,1,n){
		int l=cun[i].l,r=cun[i].r;
		if(l!=0) add1[r].push_back(l);
		if(i-1>=l+1&&r<=n) add_r[r].push_back((xixi){l+1,i-1});
		if(r-1>=i+1&&l>=1) add_l[l].push_back((xixi){i+1,r-1});
	}
	pos(i,1,n){
		int k;
		k=add1[i].size()-1;
		if(k<0)	root1[i]=root1[i-1];
		else{
			int t1=root1[i-1],t2;
			pos(j,0,k){
				t2=t1;
				update1(t2,1,n,add1[i][j]);
				t1=t2;
			}
			root1[i]=t1;
		}
		k=add_r[i].size()-1;
		if(k<0) root_r[i]=root_r[i-1];
		else{
			int t1=root_r[i-1],t2(0);
			pos(j,0,k){
				update_r(t1,t2,1,n,add_r[i][j].l,add_r[i][j].r);
				t1=t2;t2=0;
			}
			root_r[i]=t1;
		}	
	}
	pos2(i,n,1){
		int k=add_l[i].size()-1;
		if(k<0){
			root_l[i]=root_l[i+1];
		}
		else{
			int t1=root_l[i+1],t2(0);
			pos(j,0,k){
				update_l(t1,t2,1,n,add_l[i][j].l,add_l[i][j].r);
				t1=t2;t2=0;
			}
			root_l[i]=t1;
		}
	}
	LL ans(0);
	pos(i,1,m){
		ans=0;
		int x,y;scanf("%d%d",&x,&y);
		ans+=(query1(root1[x-1],root1[y],1,n,x)+(y-x))*1ll*p1;
		ans+=query_r(root_r[x-1],root_r[y],0,1,n,x)*1ll*p2;
		ans+=query_l(root_l[x],root_l[y+1],0,1,n,y)*1ll*p2;
		printf("%lld\n",ans);
	}
	return 0;
}

  

[BZOJ 4826]影魔 區間修改主席樹 標記永久化