题面传送门

首先我们把这两个贡献翻译成人话:

  • 区间 \([l,r]\) 产生 \(p_1\) 的贡献当且仅当 \(a_l,a_r\) 分别为区间 \([l,r]\) 的最大值和次大值。
  • 区间 \([l,r]\) 产生 \(p_2\) 的贡献当且仅当 \(a_l\) 为区间 \([l,r]\) 的最大值且 \(a_r\) 不是区间 \([l,r]\) 的次大值,或者 \(a_r\) 为区间 \([l,r]\) 的最大值且 \(a_l\) 不是区间 \([l,r]\) 的次大值。

我们考虑转化贡献体,对于每个区间 \([l,r]\) 分两种情况:

  • 若 \(r-l=1\),那么显然所有这样的区间都会产生 \(p_1\) 的贡献,这个我们特判一下即可。
  • 若 \(r-l\ge 2\),那么显然对于区间 \([l+1,r-1]\) 有一个唯一的最大值,设其位置为 \(i\),于是我们改枚举 \(i\),看看它会对哪些区间产生贡献。

我们设 \(L_i\) 为在 \(i\) 前面的最靠近 \(i\) 的满足 \(a_j>a_i\) 的 \(j\),\(R_i\) 为在 \(i\) 后面的最靠近 \(i\) 的满足 \(a_j>a_i\) 的 \(j\),这个显然可以一遍单调栈求出,然后分情况讨论:

  • 若 \(i\) 为区间 \([l+1,r-1]\) 的最大值,且区间 \([l,r]\) 产生 \(p_1\) 的贡献,那显然只能是 \(l=L_i,r=R_i\),因为如果左端点 \(l>L_i\) 那 \(a_l\) 就不是 \([l,r]\) 的较大值(或次大值)了(因为 \(a_l<a_i\)),如果左端点 \(l<L_i\) 那 \(a_i\) 就不是 \([l+1,r-1]\) 的最大值了(因为 \(a_{L_i}>a_i\));右端点同理。
  • 若 \(i\) 为区间 \([l+1,r-1]\) 的最大值,且区间 \([l,r]\) 产生 \(p_2\) 的贡献,那我们分最大值在左端点处和最大值在右端点处两种情况。这里以最大值在左端点处为例,显然 \(l=L_i\),而右端点理论上来说可以取遍 \((L_i,R_i)\) 中所有值,而我们强制 \(i\) 为区间 \([l+1,r-1]\) 的最大值,故 \(r\in(i,R_i)\)。也就是说 \(l=L_i,r\in(i,R_i)\),另一半同理可得 \(r=R_i,l\in(L_i,i)\)。

考虑借鉴 P5445 [APIO2019]路灯 的套路,建立二维平面直角坐标系,点 \((i,j)\) 表示以 \(i,j\) 为端点的区间的贡献,那么显然对于每组询问我们只需求出以 \((l,l)\) 左下角,\((r,r)\) 为右下角的矩形中所有数的和。而显然上面的贡献都可转化为”纵坐标为 \(y\),横坐标在区间 \([l,r]\) 中的点的贡献增加 \(v\) 的形式“。那么显然我们可以把询问进行差分处理,并离线扫描线+线段树回答每个询问,复杂度线对。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=1;
while(!isdigit(c)){if(c=='-') neg=-1;c=getchar();}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
x*=neg;
}
const int MAXN=2e5;
int n,m,qu=0,p1,p2,a[MAXN+5],L[MAXN+5],R[MAXN+5];
struct node{int l,r;ll sum,lz;} s[MAXN*4+5];
void build(int k,int l,int r){
s[k].l=l;s[k].r=r;if(l==r) return;
int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
void pushdown(int k){
if(s[k].lz){
s[k<<1].sum+=1ll*(s[k<<1].r-s[k<<1].l+1)*s[k].lz;s[k<<1].lz+=s[k].lz;
s[k<<1|1].sum+=1ll*(s[k<<1|1].r-s[k<<1|1].l+1)*s[k].lz;s[k<<1|1].lz+=s[k].lz;
s[k].lz=0;
}
}
void modify(int k,int l,int r,int x){
if(l<=s[k].l&&s[k].r<=r){
s[k].sum+=1ll*x*(s[k].r-s[k].l+1);
s[k].lz+=x;return;
} pushdown(k);int mid=(s[k].l+s[k].r)>>1;
if(r<=mid) modify(k<<1,l,r,x);
else if(l>mid) modify(k<<1|1,l,r,x);
else modify(k<<1,l,mid,x),modify(k<<1|1,mid+1,r,x);
s[k].sum=s[k<<1].sum+s[k<<1|1].sum;
}
ll query(int k,int l,int r){
if(l<=s[k].l&&s[k].r<=r) return s[k].sum;
pushdown(k);int mid=(s[k].l+s[k].r)>>1;
if(r<=mid) return query(k<<1,l,r);
else if(l>mid) return query(k<<1|1,l,r);
else return query(k<<1,l,mid)+query(k<<1|1,mid+1,r);
}
vector<pair<pii,int> > add[MAXN+5];
stack<pii> stk;ll ans[MAXN+5];
struct query{
int x,l,r,p,t;
bool operator <(const query &rhs){return x<rhs.x;}
} q[MAXN*2+5];
int main(){
scanf("%d%d%d%d",&n,&m,&p1,&p2);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
while(!stk.empty()&&stk.top().fi<a[i]) R[stk.top().se]=i,stk.pop();
stk.push(mp(a[i],i));
} while(!stk.empty()) R[stk.top().se]=n+1,stk.pop();
for(int i=n;i;i--){
while(!stk.empty()&&stk.top().fi<a[i]) L[stk.top().se]=i,stk.pop();
stk.push(mp(a[i],i));
} while(!stk.empty()) L[stk.top().se]=0,stk.pop();
for(int i=1;i<=n;i++){
if(L[i]&&R[i]!=n+1) add[L[i]].pb(mp(mp(R[i],R[i]),p1));
if(L[i]&&R[i]!=i+1) add[L[i]].pb(mp(mp(i+1,R[i]-1),p2));
if(R[i]!=n+1&&L[i]!=i-1) add[R[i]].pb(mp(mp(L[i]+1,i-1),p2));
}
for(int i=1;i<=m;i++){
int l,r;scanf("%d%d",&l,&r);ans[i]+=1ll*(r-l)*p1;
q[++qu]={r,l,r,i,1};q[++qu]={l-1,l,r,i,-1};
} build(1,1,n);
sort(q+1,q+qu+1);int cur=1;
for(int i=1;i<=qu;i++){
while(cur<=q[i].x){
ffe(it,add[cur]) modify(1,it->fi.fi,it->fi.se,it->se);
cur++;
} ans[q[i].p]+=q[i].t*query(1,q[i].l,q[i].r);
}
for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}

P3722 [AH2017/HNOI2017]影魔(单调栈+扫描线+线段树)的更多相关文章

  1. 【BZOJ4826】[Hnoi2017]影魔 单调栈+扫描线

    [BZOJ4826][Hnoi2017]影魔 Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝 ...

  2. Codeforces 407E - k-d-sequence(单调栈+扫描线+线段树)

    Codeforces 题面传送门 & 洛谷题面传送门 深感自己线段树学得不扎实-- 首先特判掉 \(d=0\) 的情况,显然这种情况下满足条件的区间 \([l,r]\) 中的数必须相同,双针扫 ...

  3. 【bzoj4826】[Hnoi2017]影魔 单调栈+可持久化线段树

    题目描述 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己 ...

  4. BZOJ 4826: [Hnoi2017]影魔 单调栈+可持久化线段树

    Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样 的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个 ...

  5. 洛谷P3722 [AH2017/HNOI2017]影魔(线段树)

    题意 题目链接 Sol 题解好神仙啊qwq. 一般看到这种考虑最大值的贡献的题目不难想到单调数据结构 对于本题而言,我们可以预处理出每个位置左边第一个比他大的位置\(l_i\)以及右边第一个比他大的位 ...

  6. [BZOJ4826] [HNOI2017] 影魔 单调栈 主席树

    题面 因为是一个排列,所以不会有重复的.如果有重复就没法做了.一开始没有仔细看题目想了半天. 发现,如果是第一种情况,那么边界\(l\)和\(r\)就应该分别是整个区间的最大值和次大值. 然后,对于那 ...

  7. BZOJ 4826: [Hnoi2017]影魔 单调栈 主席树

    https://www.lydsy.com/JudgeOnline/problem.php?id=4826 年少不知空间贵,相顾mle空流泪. 和上一道主席树求的东西差不多,求两种对 1. max(a ...

  8. 51NOD 1962 区间计数 单调栈+二分 / 线段树+扫描线

     区间计数   基准时间限制:1.5 秒 空间限制:262144 KB 分值: 80   两个数列 {An} , {Bn} ,请求出Ans, Ans定义如下: Ans:=Σni=1Σnj=i[max{ ...

  9. 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)

    线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...

随机推荐

  1. UltraSoft - DDL Killer - Alpha 项目展示

    团队介绍 CookieLau fmh 王 FUJI LZH DZ Monster PM & 后端 前端 前端 前端 后端 后端 软件介绍 项目简介 项目名称:DDLKiller 项目描述:&q ...

  2. BUAA软件工程个人项目作业

    BUAA软件工程个人项目作业 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人项目作业 我在这个课程的目标是 学习软件开发的流程 这个作业在哪 ...

  3. proto3语法记录

    protobuf 是谷歌的语言无关,平台无关,可扩展的,高效的结构化数据序列化机制,比xml和json的序列化的速度更快,此处记录一下 proto3 的语法,防止以后忘记. 注意:proto3 语法需 ...

  4. Allegro如何测量距离,测距工具的使用

    http://www.allegro-skill.com/thread-2480-1-1.html

  5. CentOS8 部署 MySQL8

    前言 有来项目的数据库在此之前使用的是 Docker 部署的,具体可见文章 Docker 安装 MySQL8 ,服务器是阿里云 2C2G 的ECS轻量服务器,可能是配置问题有时不论查什么都要等很长很长 ...

  6. Python 调用上级目录的文件

    程序结构如下: – src |-- mod1.py |-- lib | |-- mod2.py |-- sub | |-- test.py 具体代码如下: 在test.py里调用mod1 mod2 i ...

  7. zabbix 报警发送企业威信

    1.组册企业微信,创建应用 2.下载脚本文件: https://raw.githubusercontent.com/OneOaaS/weixin-alert/master/weixin_linux_a ...

  8. APP自动化之Hybrid自动化解决方案(七)

    基于UIAutomator+ChromeDriver模式(UIAutomator安卓原生引擎) 原理:native(原生)部分使用UIAutomator,webview部分使用ChromeDriver ...

  9. properties 文件解析

    1.提供properties文件 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/future?useUn ...

  10. 重装系统——联想window 10

    大四了,读了四年大学,唉,混的,啥也不会,工作也找不到,真的不知道这大学四年到底干了什么.专业是计算机方向的,但居然,不敢,也不会装电脑系统,大学四年的文件都是乱放的,更那个的是,有些软件卸载不完全, ...