题解:[AHOI2017/HNOI2017] 影魔

题目传送门

题意分析

\(p_1,p_2\) 无关,分开计算贡献是显然的。

考虑如何刻画贡献。

记询问区间为 \([l,r]\),原序列为 \(a_1,a_2,\cdots,a_n\)

那么:

  • \((i,j)\) 产生 \(p_1\) 贡献当且仅当(和 \(j=i+1\) 时恒有 \(p_1\) 贡献):

    \[\max_{k=i+1}^{j-1}a_k<\min(a_i,a_j) \]

  • \((i,j)\) 产生 \(p_2\) 贡献有两种方式:

    \[\begin{aligned} a_i<&\max_{i=i+1}^{j-1}<a_j\\ a_j<&\max_{i=i+1}^{j-1}<a_i\\ \end{aligned} \]

\(a_x\)\(a_{i+1},a_{i+2},\cdots,a_{j-1}\) 中的最大值,则三种贡献都与 \(x\) 有关。

发现通过 \((i,j)\)\(x\) 不能优化,正难则反,考虑通过 \(x\) 统计 \((i,j)\) 的贡献。

\(L_i,R_i\) 分别为 \(i\) 左边、右边的第一个大于 \(a_i\) 的位置。若不存在,则钦定 \(L_i=0\)\(R_i=n+1\)

显然有 \(L_x\leq i<x<j\leq R_x\),否则不满足 \(x\) 的定义。

  • 对于 \(p_1\)

    又因为要产生 \(p_1\) 贡献,\(i\leq L_x\)\(R_x\leq j\)

    联立不等式,解得 \((i,j)=(L_x,R_x)\)

    那么 \(x\) 对于 \([l,r]\) 的贡献便很好算的。

  • 对于 \(p_2\)

    类似地联立不等式,可知:

    • \(a_i<a_j\),为 \(i\in[L_x+1,i-1],j=R_x\)
    • \(a_j<a_i\),为 \(i=L_x,j\in[i+1,R_x-1]\)

统计答案,可以扫描线,扫过 \(a_1,a_2,\cdots,a_n\) 的似乎后对应的在区间上加贡献。

同时扫描线统计 \([l,r]\) 答案即可。

AC 代码

//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
using namespace std;
typedef long long ll;
constexpr const int N=200000,M=200000;
struct question{
	int l,r,id,w;
};
vector<question>q[N+1];
int n,m,p1,p2,a[N+1],L[N+1],R[N+1];
vector<pair<int,int>>rL[N+1+1],lR[N+1];
ll ans[M+1];
struct segTree{
	struct node{
		int l,r;
		ll value,tag;
		
		int size(){
			return r-l+1;
		}
	}t[N<<2|1];
	
	void up(int p){
		t[p].value=t[p<<1].value+t[p<<1|1].value;
	}
	void build(int p,int l,int r){
		t[p]={l,r};
		if(l==r){
			return;
		}
		int mid=l+r>>1;
		build(p<<1,l,mid);
		build(p<<1|1,mid+1,r);
		up(p);
	}
	void down(int p){
		if(t[p].tag){
			t[p<<1].value+=1ll*t[p<<1].size()*t[p].tag;
			t[p<<1].tag+=t[p].tag;
			t[p<<1|1].value+=1ll*t[p<<1|1].size()*t[p].tag;
			t[p<<1|1].tag+=t[p].tag;
			t[p].tag=0;
		}
	}
	void add(int p,int l,int r,int k){
		if(l<=t[p].l&&t[p].r<=r){
			t[p].value+=1ll*t[p].size()*k;
			t[p].tag+=k;
			return;
		}
		down(p);
		if(l<=t[p<<1].r){
			add(p<<1,l,r,k);
		}
		if(t[p<<1|1].l<=r){
			add(p<<1|1,l,r,k);
		}
		up(p);
	}
	ll query(int p,int l,int r){
		if(l<=t[p].l&&t[p].r<=r){
			return t[p].value;
		}
		down(p);
		ll ans=0;
		if(l<=t[p<<1].r){
			ans=query(p<<1,l,r);
		}
		if(t[p<<1|1].l<=r){
			ans+=query(p<<1|1,l,r);
		}
		return ans;
	}
}t;
void pre(){
	vector<int>s;
	for(int i=1;i<=n;i++){
		while(s.size()&&a[s.back()]<=a[i]){
			s.pop_back();
		}
		if(s.size()){
			L[i]=s.back();
		}else{
			L[i]=0;
		}
		s.push_back(i);
	}
	s.resize(0);
	for(int i=n;1<=i;i--){
		while(s.size()&&a[s.back()]<=a[i]){
			s.pop_back();
		}
		if(s.size()){
			R[i]=s.back();
		}else{
			R[i]=n+1;
		}
		s.push_back(i);
	}
	for(int i=1;i<=n;i++){
		lR[L[i]].push_back({R[i],i});
		rL[R[i]].push_back({L[i],i});
	}
}
void solve(){
	t.build(1,0,n+1);
	 for(int i=1;i<=n;i++){
	 	for(auto x:rL[i]){
	 		t.add(1,x.first,x.first,p1);
		}
		for(auto x:rL[i]){
			t.add(1,x.first+1,x.second-1,p2);
		}
		for(auto x:lR[i]){
			t.add(1,x.second+1,x.first-1,p2);
		}
	 	for(auto x:q[i]){
	 		ans[x.id]+=x.w*t.query(1,x.l,x.r);
		}
	 }
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>n>>m>>p1>>p2;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	pre();
	for(int i=1;i<=m;i++){
		int l,r;
		cin>>l>>r;
		q[l-1].push_back({l,r,i,-1});
		q[r].push_back({l,r,i,1});
		ans[i]=1ll*(r-l)*p1;
	}
	solve();
	for(int i=1;i<=m;i++){
		cout<<ans[i]<<'\n';
	}
	
	cout.flush();
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
posted @ 2026-02-05 11:30  TH911  阅读(3)  评论(0)    收藏  举报