BZOJ4826: [Hnoi2017]影魔

BZOJ4826: [Hnoi2017]影魔

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

题解Here!
我们发现要处理一堆区间$emmm...$
话说这题能不能用区间神器莫队呢?
好像不能欸,因为我没有想出来区间和值不好转变。
我们发现对于$p_1$类型的区间$[i,j]$。
如果$j>i$那么$j$一定是$i$右侧第一个比它大的点。
什么?$j<i$?,反转区间可以转化成情况一。
再考虑$p_2$情况类型的区间$[i,j]$
如果$i$小于$j$,则$i$一定是这样的点:它在区间$(p,q)$之间
$(p,q)$是开区间!!!
其中$[q.j]$是一个$p_1$类型的区间,$p$是$q$左侧第一个比q大的点。
同理$i>j$是可以反转区间转换为情况一。
通过反证法我们可以很容易的证明上面的说法可以不重不漏的
枚举出所有的$p_1,p_2$(假设有一个不符合条件的区间,发现很快就会出矛盾)。
发现上述一套花里胡哨的定义只需要两个信息:
点$i$左侧第一个比他大的点是谁;
点$i$右侧第一个比他大的点是谁。
这。。。当然单调栈$O(n)$预处理啊。。。
接下来是统计区间。
发现在线处理会直接晕掉,考虑离线处理。。。
把询问按右端点排序,之后每次拓展右端点。
更新所有合法的左端点即可。
然后我们发现$p_1$是单点修改,$p_2$是区间修改。
结果一堆大佬直接树状数组。。。
本蒟蒻表示根本不会。。。
于是直接上线段树。。。
然后线段树求一下就是结果了。
$BUT$!上述只处理了一半,即$i$小于$j$。
那另外一半呢?
我们可以把区间和询问统统反转,处理下一半情况。
细节看代码吧,不看代码刚才讲的好多细节没有。。。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) a[x].data
#define SIGN(x) a[x].c
#define LSIDE(x) a[x].l
#define RSIDE(x) a[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
#define MAXN 200010
using namespace std;
int n,m,top;
int next[MAXN],stack[MAXN];
long long p1,p2,val[MAXN],ans[MAXN];
struct Sg_Tree{
	long long data,c;
	int l,r;
}a[MAXN<<2];
struct node{
	int l,r,id;
}que[MAXN];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
bool cmp(const node &x,const node &y){
	if(x.l==y.l)return x.r<y.r;
	return x.l<y.l;
}
inline void pushup(int rt){
	DATA(rt)=DATA(LSON)+DATA(RSON);
}
inline void pushdown(int rt){
	if(!SIGN(rt)||LSIDE(rt)==RSIDE(rt))return;
	SIGN(LSON)+=SIGN(rt);
	DATA(LSON)+=SIGN(rt)*WIDTH(LSON);
	SIGN(RSON)+=SIGN(rt);
	DATA(RSON)+=SIGN(rt)*WIDTH(RSON);
	SIGN(rt)=0;
}
void buildtree(int l,int r,int rt){
	int mid;
	LSIDE(rt)=l;
	RSIDE(rt)=r;
	SIGN(rt)=0;
	if(l==r){
		DATA(rt)=0;
		return;
	}
	mid=l+r>>1;
	buildtree(l,mid,LSON);
	buildtree(mid+1,r,RSON);
	pushup(rt);
}
void update(int l,int r,long long c,int rt){
	int mid;
	if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
		SIGN(rt)+=c;
		DATA(rt)+=c*WIDTH(rt);
		return;
	}
	pushdown(rt);
	mid=LSIDE(rt)+RSIDE(rt)>>1;
	if(l<=mid)update(l,r,c,LSON);
	if(mid<r)update(l,r,c,RSON);
	pushup(rt);
}
long long query(int l,int r,int rt){
	int mid;
	long long ans=0;
	if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
	pushdown(rt);
	mid=LSIDE(rt)+RSIDE(rt)>>1;
	if(l<=mid)ans+=query(l,r,LSON);
	if(mid<r)ans+=query(l,r,RSON);
	return ans;
}
int half_find(int x){
	int left=1,right=m+1,mid;
	while(left<=right){
		mid=left+right>>1;
		if(que[mid].l<x)left=mid+1;
		else right=mid-1;
	}
	return left;
}
void work(){
	top=0;
	stack[top]=n+1;
	buildtree(1,n+1,1);
	for(int i=n;i>=1;i--){
		while(top&&val[stack[top]]<val[i])stack[top--]=0;
		next[i]=stack[top];
		stack[++top]=i;
	}
	for(int i=n;i>=1;i--){
		if(next[i]>i){
			update(i+1,next[i],p2,1);
			update(next[i],next[i],p1-p2*2,1);
		}
		int pos=half_find(i);
		while(que[pos].l==i){
			ans[que[pos].id]+=query(i+1,que[pos].r,1);
			pos++;
		}
	}
}
void init(){
	n=read();m=read();p1=read();p2=read();
	for(int i=1;i<=n;i++)val[i]=read();
	for(int i=1;i<=m;i++){
		que[i].l=read();que[i].r=read();
		que[i].id=i;
	}
	sort(que+1,que+m+1,cmp);
	work();
	for(int i=1;i<=n/2;i++)swap(val[i],val[n-i+1]);
	for(int i=1;i<=m;i++){
		swap(que[i].l,que[i].r);
		que[i].l=n-que[i].l+1;
		que[i].r=n-que[i].r+1;
	}
	sort(que+1,que+m+1,cmp);
	work();
	for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
}
int main(){
	init();
	return 0;
}

 

posted @ 2018-08-12 21:18  符拉迪沃斯托克  阅读(298)  评论(0编辑  收藏  举报
Live2D