BZOJ 4826: [Hnoi2017]影魔

4826: [Hnoi2017]影魔

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 212  Solved: 114
[Submit][Status][Discuss]

Description

影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样
的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。每一个灵魂,都有着自己的战斗力,而影魔,靠
这些战斗力提升自己的攻击。奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n。
第 i个灵魂的战斗力为 k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 i,j(i<j)来说,若不存在 k[s](i
<s<j)大于 k[i]或者 k[j],则会为影魔提供 p1 的攻击力(可理解为:当 j=i+1 时,因为不存在满足 i<s<j 的 s,从
而 k[s]不存在,这时提供 p1 的攻击力;当 j>i+1 时,若max{k[s]|i<s<j}<=min{k[i],k[j]} , 则 提 供 p1 的 攻
 击 力 ); 另 一 种 情 况 , 令 c 为k[i+1],k[i+2],k[i+3]......k[j-1]的最大值,若 c 满足:k[i]<c<k[j],或
者 k[j]<c<k[i],则会为影魔提供 p2 的攻击力,当这样的 c 不存在时,自然不会提供这 p2 的攻击力;其他情况的
点对,均不会为影魔提供攻击力。影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任
意一段区间[a,b],1<=a<b<=n,位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑 所有满足a<=i<j<=b 的灵
魂对 i,j 提供的攻击力之和。顺带一提,灵魂的战斗力组成一个 1 到 n 的排列:k[1],k[2],...,k[n]。

Input

第一行 n,m,p1,p2
第二行 n 个数:k[1],k[2],...,k[n]
接下来 m 行,每行两个数 a,b,表示询问区间[a,b]中的灵魂对会为影魔提供多少攻击力。
1 <= n,m <= 200000;1 <= p1,p2 <= 1000

Output

共输出 m 行,每行一个答案,依次对应 m 个询问。

Sample Input

10 5 2 3
7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5

Sample Output

30
39
4
13
16

HINT

Source

分析:

我们考虑每个值作为区间最大值的时候,可以产生的合法点对的贡献...

考虑对于每个点预处理出来$l[i]$和$r[i]$,分别表示$i$左边第一个比$a[i]$大的位置和右边第一个比$a[i]$大的位置...那么区间$[l[i]+1,r[i]-1]$代表的是极大的以$a[i]$为最大值的区间...

那么点对$(l[i],r[i])$的贡献就是$p1$,$(l[i],i+1~r[i]-1)$和$(l[i]+1~i-1,r[i])$的贡献为$p2$,其他点对的贡献就是$0$了...

欸,这就是一个区间加区间询问的问题...考试的时候写的在线,用可持久化线段树维护区间的和...但是考完发现可以离线用线段树维护...

代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
//by NeighThorn
using namespace std;

const int maxn=200000+5,maxm=8000000+5;

int n,m,p1,p2,top,a[maxn],lef[maxn],rig[maxn],stk[maxn];
long long ans;

struct M{
	
	int tot,ls[maxm],rs[maxm],root[maxn*3];
	long long sum[maxm],add[maxm];
	
	inline void init(void){
		tot=0;
		memset(sum,0,sizeof(sum));
		memset(root,0,sizeof(root));
	}
	
	inline void change(int l,int r,int x,int &y,int L,int R,int val){
		if(L>R) return;
		y=++tot;sum[y]=sum[x]+(R-L+1)*val;add[y]=add[x];
		ls[y]=ls[x];rs[y]=rs[x];
		if(l==L&&R==r){
			add[y]+=val;return;
		}
		int mid=l+r>>1;
		if(R<=mid)
			change(l,mid,ls[x],ls[y],L,R,val);
		else if(L>mid)
			change(mid+1,r,rs[x],rs[y],L,R,val);
		else
			change(l,mid,ls[x],ls[y],L,mid,val),change(mid+1,r,rs[x],rs[y],mid+1,R,val);
	}
	
	inline long long query(int l,int r,int x,int y,int L,int R){
		if(l==L&&r==R)
			return sum[y]-sum[x];
		int mid=l+r>>1;long long ans=1LL*(R-L+1)*(add[y]-add[x]);
		if(R<=mid)
			ans+=query(l,mid,ls[x],ls[y],L,R);
		else if(L>mid)
			ans+=query(mid+1,r,rs[x],rs[y],L,R);
		else
			ans+=query(l,mid,ls[x],ls[y],L,mid)+query(mid+1,r,rs[x],rs[y],mid+1,R);
		return ans;
	}
	
}tr1,tr2;

struct N{
	
	int cnt,l[maxn*3],r[maxn*3],hd[maxn],val[maxn*3],nxt[maxn*3];
	
	inline void init(void){
		memset(hd,-1,sizeof(hd));cnt=0;
	}
	
	inline void add(int x,int L,int R,int v){
//		cout<<x<<" "<<L<<" "<<R<<" "<<v<<endl;
		l[cnt]=L,r[cnt]=R,val[cnt]=v,nxt[cnt]=hd[x],hd[x]=cnt++;
	}
	
}tree1,tree2;

inline int read(void){
	char ch=getchar();int x=0;
	while(!(ch>='0'&&ch<='9')) ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x;
}

signed main(void){
//	freopen("sf.in","r",stdin);
//	freopen("sf.out","w",stdout);
	n=read(),m=read(),p1=read(),p2=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int i=1;i<=n;i++){
		while(top&&a[stk[top]]<a[i]) rig[stk[top]]=i,top--;
		stk[++top]=i;
	}
	while(top) rig[stk[top--]]=n+1;
	for(int i=n;i>=1;i--){
		while(top&&a[stk[top]]<a[i]) lef[stk[top]]=i,top--;
		stk[++top]=i;
	}
	while(top) lef[stk[top--]]=0;
	tree1.init();tree2.init();
	for(int i=1;i<=n;i++){
		tree1.add(lef[i],rig[i],rig[i],p1);
		if(i+1<=rig[i]-1)
//			cout<<"L: ",
			tree1.add(lef[i],i+1,rig[i]-1,p2);
		if(lef[i]+1<=i-1)
//			cout<<"R: ",
			tree2.add(rig[i],lef[i]+1,i-1,p2);
	}
//	puts("finish prework");
	tr1.init();tr2.init();
	for(int x=1;x<=n;x++){
		tr1.root[x]=tr1.root[x-1];
		for(int i=tree1.hd[x];i!=-1;i=tree1.nxt[i])
//			cout<<"L: "<<x<<" "<<tree1.l[i]<<" "<<tree1.r[i]<<" "<<tree1.val[i]<<endl,
			tr1.change(1,n,tr1.root[x],tr1.root[x],max(1,tree1.l[i]),min(n,tree1.r[i]),tree1.val[i]);
	}
	for(int x=n;x>=1;x--){
		tr2.root[x]=tr2.root[x+1];
		for(int i=tree2.hd[x];i!=-1;i=tree2.nxt[i])
//			cout<<"R: "<<x<<" "<<tree2.l[i]<<" "<<tree2.r[i]<<" "<<tree2.val[i]<<endl,
			tr2.change(1,n,tr2.root[x],tr2.root[x],max(1,tree2.l[i]),min(n,tree2.r[i]),tree2.val[i]);
	}
	for(int i=1,x,y;i<=m;i++){
		x=read(),y=read();ans=(y-x)*p1;
		ans+=tr1.query(1,n,tr1.root[x-1],tr1.root[y],x,y);
		ans+=tr2.query(1,n,tr2.root[y+1],tr2.root[x],x,y);
		printf("%lld\n",ans);
	}
//	fclose(stdin);fclose(stdout);
	return 0;
}

  


By NeighThorn

posted @ 2017-04-19 21:09  NeighThorn  阅读(340)  评论(0编辑  收藏  举报