P3722 [AH2017/HNOI2017]影魔(单调栈+扫描线+线段树)
首先我们把这两个贡献翻译成人话:
- 区间 \([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]影魔(单调栈+扫描线+线段树)的更多相关文章
- 【BZOJ4826】[Hnoi2017]影魔 单调栈+扫描线
[BZOJ4826][Hnoi2017]影魔 Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝 ...
- Codeforces 407E - k-d-sequence(单调栈+扫描线+线段树)
Codeforces 题面传送门 & 洛谷题面传送门 深感自己线段树学得不扎实-- 首先特判掉 \(d=0\) 的情况,显然这种情况下满足条件的区间 \([l,r]\) 中的数必须相同,双针扫 ...
- 【bzoj4826】[Hnoi2017]影魔 单调栈+可持久化线段树
题目描述 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己 ...
- BZOJ 4826: [Hnoi2017]影魔 单调栈+可持久化线段树
Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样 的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个 ...
- 洛谷P3722 [AH2017/HNOI2017]影魔(线段树)
题意 题目链接 Sol 题解好神仙啊qwq. 一般看到这种考虑最大值的贡献的题目不难想到单调数据结构 对于本题而言,我们可以预处理出每个位置左边第一个比他大的位置\(l_i\)以及右边第一个比他大的位 ...
- [BZOJ4826] [HNOI2017] 影魔 单调栈 主席树
题面 因为是一个排列,所以不会有重复的.如果有重复就没法做了.一开始没有仔细看题目想了半天. 发现,如果是第一种情况,那么边界\(l\)和\(r\)就应该分别是整个区间的最大值和次大值. 然后,对于那 ...
- BZOJ 4826: [Hnoi2017]影魔 单调栈 主席树
https://www.lydsy.com/JudgeOnline/problem.php?id=4826 年少不知空间贵,相顾mle空流泪. 和上一道主席树求的东西差不多,求两种对 1. max(a ...
- 51NOD 1962 区间计数 单调栈+二分 / 线段树+扫描线
区间计数 基准时间限制:1.5 秒 空间限制:262144 KB 分值: 80 两个数列 {An} , {Bn} ,请求出Ans, Ans定义如下: Ans:=Σni=1Σnj=i[max{ ...
- 有趣的线段树模板合集(线段树,最短/长路,单调栈,线段树合并,线段树分裂,树上差分,Tarjan-LCA,势能线段树,李超线段树)
线段树分裂 以某个键值为中点将线段树分裂成左右两部分,应该类似Treap的分裂吧(我菜不会Treap).一般应用于区间排序. 方法很简单,就是把分裂之后的两棵树的重复的\(\log\)个节点新建出来, ...
随机推荐
- silky微服务快速开始
项目介绍 Silky框架旨在帮助开发者在.net平台下,通过简单代码和配置快速构建一个微服务开发框架. Silky 通过 .net core的主机来托管微服务应用.通过 Asp.Net Core 提供 ...
- 微服务网关Ocelot加入IdentityServer4鉴权-.NetCore(.NET5)中使用
Consul+Ocelot+Polly在.NetCore中使用(.NET5)-Consul服务注册,服务发现 Consul+Ocelot+Polly在.NetCore中使用(.NET5)-网关Ocel ...
- Clusternet v0.5.0 重磅发布: 全面解决多集群应用分发的差异化配置难题
作者 徐迪,腾讯云容器技术专家. 汝英哲,腾讯云高级产品经理. 摘要 在做多集群应用分发的时候,经常会遇到以下的差异化问题,比如: 在分发的资源上全部打上统一的标签,比如 apps.my.compan ...
- 初学python写个自娱自乐的小游戏
一.摘要 当编写完后的代码执行第一次后达到了目标的预期效果,内心有些许满足,但是当突发情况产生后,程序便不能正常运行,于是准备从简单的版本开始出发,综合考虑使用者的需求,和使用过程中会遇到的问题,一步 ...
- 【二食堂】Beta - Scrum Meeting 2
Scrum Meeting 2 例会时间:5.14 18:30~18:50 进度情况 组员 当前进度 今日任务 李健 1. 还在进行摸索,目前做出了一个demo可以进行简单的划词 issue 1. 继 ...
- 期望dp好题选做
前言: 最近连考两场期望dp的题目,sir说十分板子的题目我竟然一点也不会,而且讲过以后也觉得很不可改.于是开个坑. 1.晚测10 T2 大佬(kat) 明明有\(O(mlog)\)的写法,但是\(m ...
- lib库无法加载的情况分析
最近升级vs2017的时候遇到无法加载库的问题,在网上查找问题,网上给出可能有三种情况导致该问题:路径是否正确:库依赖是否齐全:库版本是否正确.最直接的方法就是用depends软件去查询,是否有模块有 ...
- 单片机stm32串口分析
stm32作为现在嵌入式物联网单片机行业中经常要用多的技术,相信大家都有所接触,今天这篇就给大家详细的分析下有关于stm32的出口,还不是很清楚的朋友要注意看看了哦,在最后还会为大家分享有些关于stm ...
- RocketMQ源码详解 | Broker篇 · 其一:线程模型与接收链路
概述 在上一节 RocketMQ源码详解 | Producer篇 · 其二:消息组成.发送链路 中,我们终于将消息发送出了 Producer,在短暂的 tcp 握手后,很快它就会进入目的 Broker ...
- Envoy实现.NET架构的网关(四)集成IdentityServer4实现OAuth2认证
什么是OAuth2认证 简单说,OAuth 就是一种授权机制.数据的所有者告诉系统,同意授权第三方应用进入系统,获取这些数据.系统从而产生一个短期的进入令牌(token),用来代替密码,供第三方应用使 ...