LOJ #2019. 「AHOI / HNOI2017」影魔

前言

HNOI作为Hard NOI,题目质量还是很高的(扯淡)
其中考查的数据结构非常简单,但是很锻炼思维能力.

正题

一开始看到时空限制想试试莫队 O ( n n ) O(n*\sqrt n) ,但是好像不行.
然后,推出一堆结论就去看题解了

L [ i ] , R [ i ] k i L[i],R[i]表示值大于k_i的左右最近位置
则对于产生 p 1 p1 贡献当且仅当:

  1. ( i , i + 1 ) , i [ a , b ) (i,i+1),i\in[a,b)
  2. a L [ i ]    a n d   R [ i ] b    a n d    i ( a , b ) a\le L[i]~~ and ~R[i]\le b~~ and ~~ i\in (a,b)

对于产生 p 2 p2 贡献的次数为满足以下条件的次数:( j [ a , b ] j\in [a,b] )
( i , j , k ) , i < j < k , m a x ( L [ j ] , a 1 ) < i , k < m i n ( R [ j ] , b 1 ) (i,j,k),i<j<k,max(L[j],a-1)<i,k<min(R[j],b-1)

更具体的实现方式:
当扫到 R [ i ] R[i] 时,把 L [ i ] L[i] 的贡献加 p 1 p1 ,把 [ L [ i ] + 1 , i 1 ] [L[i]+1,i-1] 的贡献加 p 2 p2
当扫到 L [ i ] L[i] 时,把 [ i + 1 , R [ i ] ] [i+1,R[i]] 的贡献加 p 2 p2 .

处理方法:
顺序处理每个位置的贡献,那么询问 [ l , r ] [l,r] 的答案就是 ( r ) ( l 1 ) (r时的答案)-(l-1时的答案) .(用树状数组维护前缀和)
就是排除掉前 l 1 l-1 个位置的影响.

ps:auto 是c++11以上才有的

#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define gc getchar()//(p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++)
using namespace std;
typedef long long ll;
const int N=2e5+10,size=1<<20;

//char buf[size],*p1=buf,*p2=buf;
template<class o> void qr(o &x) {
	char c=gc; x=0; int f=1;
	while(!isdigit(c)){if(c=='-')f=-1; c=gc;}
	while(isdigit(c)) x=x*10+c-'0',c=gc;
	x*=f;
}
template<class o> void qw(o x) {
	if(x/10) qw(x/10);
	putchar(x%10+'0');
}
template<class o> void pr2(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); puts("");
}

int n,m,p1,p2,a[N],L[N],R[N],sta[N],top;

ll c1[N],c2[N],ans[N];
void add(int x,int y) {
	ll z=(ll)x*y;
	if(x)while(x<=n) c1[x]+=y,c2[x]+=z,x+=x&-x;
}
ll ask(int x) {
	ll s=0;
	for(int i=x; i;i-=i&-i) s+=(x+1)*c1[i]-c2[i];
	return s;
}

struct node {
	int l,r,id,d;
};
vector<node> q[N],o[N];//query,option

int main() {
	qr(n); qr(m); qr(p1); qr(p2); a[0]=a[n+1]=n+1;
	for(int i=1;i<=n;i++) {
		qr(a[i]);
		while(a[sta[top]]<a[i]) R[sta[top--]]=i;
		L[i]=sta[top]; sta[++top]=i;
	}
	while(top) R[sta[top--]]=n+1;
	
	for(int i=1,l,r;i<=m;i++) {
		qr(l); qr(r);
		q[r].push_back((node){l,r,i,1});
		q[l-1].push_back((node){l,r,i,-1});
		ans[i]=(r-l)*p1;
	}
	
	for(int i=1,l,r;i<=n;i++) {
		l=L[i]; r=R[i];
		if(i+1<=r-1)o[l].push_back((node){i+1,r-1,0,p2});
		if(l) o[r].push_back((node){l,l,0,p1});
		if(l+1<=i-1)o[r].push_back((node){l+1,i-1,0,p2});
	}
	
	for(int i=1;i<=n;i++) {
		for(auto now:o[i]) 
			add(now.r+1,-now.d),
			add(now.l,now.d);
		for(auto now:q[i]) 
			ans[now.id]+=now.d*(ask(now.r)-ask(now.l-1));
	}
	
	for(int i=1;i<=m;i++) pr2(ans[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/105665679