[BZOJ4826][HNOI2017]影魔 可持久化线段树

链接

题意:给你 (1)(n) 的排列 (k_1,k_2,dots,k_n) ,对 (i,j (i<j))来说,若不存在 (k_s (i<s<j)) 大于 (k_i) 或者 (k_j),则会产生 (p_1) 的贡献。另一种情况,令 (c)(k_{i + 1}, k_{i + 2}, cdots, k_{j -1}) 的最大值,若 (c) 满足:(k_i < c < k_j),或者 (k_j < c < k_i),则会为产生 (p_2) 的贡献 ,多次询问区间 ([l_i,r_i]) 的贡献值

题解

第一种情况,(k_i)(k_j)([i,j]) 的最大值和次大值,第二种情况,是最大值和第三大值

对于每个 (i) ,用单调栈预处理出它左边第一个比他大的位置 (lpos[i]) ,右边第一个比他大的位置 (rpos[i]) ,那么第一种情况是所有的 (lpos[i],rpos[i])(i,i+1) (前者并不会算重复),第二种情况是所有的 (lpos[i],i+1dots rpos[i]-1)(lpos[i]+1dots i-1,rpos[i])

由于是询问区间 ([l,r]) 的值,而且发现上述所有的点对,某一点都是定的,因此开一棵可持久化线段树搞一下这个(相当于查询二维坐标系下 ((l,l))((r,r)) 这个矩形区域的值)

好像有扫描线的做法,不过我不会扫描线,先留个坑以后再补(咕咕咕)

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i(a);i<=(b);++i)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
const int S=1<<18;
char ibuf[S],*iS,*iT;
#define gc (iS==iT?iT=ibuf+fread(iS=ibuf,1,S,stdin),iS==iT?EOF:*iS++:*iS++)
inline int read(){char c,p=0;int w;
	while(isspace(c=gc));if(c=='-')p=1,c=gc;w=c&15;
	while(isdigit(c=gc))w=w*10+(c&15);return p?-w:w;
}
template<typename T,typename U>inline bool smin(T&x,const U&y){return x>y?x=y,1:0;}
template<typename T,typename U>inline bool smax(T&x,const U&y){return x<y?x=y,1:0;}
typedef long long ll;
const int N=2e5+5;
struct node{
	int ls,rs,w;ll sum;
}t[N*70];
int n,m,p1,p2,cnt,rt[N],a[N],s[N],top,lpos[N],rpos[N];
inline void ins(int&o,int l,int r,int x,int y,int z){
	t[++cnt]=t[o];t[o=cnt].sum+=1ll*(y-x+1)*z;
	if(x<=l&&r<=y){t[o].w+=z;return;}
	int mid=l+r>>1;
	if(y<=mid)ins(t[o].ls,l,mid,x,y,z);
	else if(x>mid)ins(t[o].rs,mid+1,r,x,y,z);
	else ins(t[o].ls,l,mid,x,mid,z),ins(t[o].rs,mid+1,r,mid+1,y,z);
}
inline ll ask(int x,int y,int l,int r,int ql,int qr){
	if(ql<=l&&r<=qr)return t[y].sum-t[x].sum;
	int mid=l+r>>1;ll ans=1ll*(qr-ql+1)*(t[y].w-t[x].w);
	if(qr<=mid)return ans+ask(t[x].ls,t[y].ls,l,mid,ql,qr);
	if(ql>mid)return ans+ask(t[x].rs,t[y].rs,mid+1,r,ql,qr);
	return ans+ask(t[x].ls,t[y].ls,l,mid,ql,mid)+ask(t[x].rs,t[y].rs,mid+1,r,mid+1,qr);
}

struct data{int l,r,w;};
std::vector<data>g[N];
#define pb push_back
int main(){
	n=read(),m=read(),p1=read(),p2=read();
	REP(i,1,n)a[i]=read();
	s[top=1]=0;a[0]=a[n+1]=1e9;
	REP(i,1,n){
		while(top&&a[i]>a[s[top]])--top;
		lpos[i]=s[top];s[++top]=i;
	}
	s[top=1]=n+1;
	for(int i=n;i;--i){
		while(top&&a[i]>a[s[top]])--top;
		rpos[i]=s[top];s[++top]=i;
	}
	REP(i,1,n){
		if(i<n)g[i].pb((data){i+1,i+1,p1});
		if(lpos[i]&&rpos[i]<=n)g[lpos[i]].pb((data){rpos[i],rpos[i],p1});
		if(lpos[i]&&i<rpos[i]-1)g[lpos[i]].pb((data){i+1,rpos[i]-1,p2});
		if(rpos[i]<=n&&i>lpos[i]+1)g[rpos[i]].pb((data){lpos[i]+1,i-1,p2});
	}
	REP(i,1,n){
		rt[i]=rt[i-1];
		const int sz=g[i].size();
		for(int j=0;j<sz;++j)ins(rt[i],1,n,g[i][j].l,g[i][j].r,g[i][j].w);	
	}
	while(m--){
		int x=read(),y=read();
		printf("%lld
",ask(rt[x-1],rt[y],1,n,x,y));
	}
	return 0;
}

原文地址:https://www.cnblogs.com/HolyK/p/9920389.html