[BZOJ4826] [HNOI2017] 影魔 单调栈 主席树
因为是一个排列,所以不会有重复的。如果有重复就没法做了。一开始没有仔细看题目想了半天。
发现,如果是第一种情况,那么边界\(l\)和\(r\)就应该分别是整个区间的最大值和次大值。
然后,对于那第二种情况, \(l\)和\(r\)中,只有一个数是最大值,另一个数不可以是最大值和次大值。
于是我们考虑从每一个合法区间内数里面选出一个代表来可以直接代表整个区间。
用单调栈维护一下\(lp[i]\)和\(rp[i]\)分别表示一个数左边和右边离\(i\)最近的大于之的数。
然后对于第一种情况,发现相邻两个数一定是对的。然后发现,任何一个\([lp[i],rp[i]]\)也是对的。因为可以保证边界上的数的最大与次大的性质。
那么第二种呢?只要保证一个边界最大即可,因此就是\([lp[i]+1..i-1,rp[i]]\)和\([lp[i],i+1..rp[i]-1]\)。可以保证不会重复,因为这里\(i\)实际上是每个区间的次大值,每个区间只会被其次大值统计一次。
于是我们考虑把一个区间的边界位置分别作为二维的坐标,发现问题就变成了求以\(l,l\)和\(r,r\)为顶点的正方形内的和。
显然可以用扫描线。但是其实可以更方便。每一个位置只能是一个线段,所以我们直接用主席树维护一下即可。
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#define REP(i,a,n) for(register int i(a);i<=(n);++i)
#define PER(i,a,n) for(register int i(a);i>=(n);--i)
#define dbg(...) fprintf(stderr,__VA_ARGS__)
const int SZ=(1<<21)+1;char ibuf[SZ],*iS,*iT,obuf[SZ+128],*oS=obuf,*oT=obuf+SZ-1;
#ifndef ONLINE_JUDGE
#define gc() getchar()
#else
#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SZ,stdin),iS==iT?EOF:*iS++):*iS++)
#endif
template<typename I>inline void read(I&x){char c=gc();int f=1;for(;c<'0'||c>'9';c=gc())c=='-'?f=-1:0;for(x=0;c>='0'&&c<='9';c=gc())x=(x<<1)+(x<<3)+(c&15);f==-1?x=-x:0;}
inline void flush(){fwrite(obuf,1,oS-obuf,stdout);oS=obuf;}
#define printf(...) oS>oT&&(flush(),1),oS+=sprintf(oS,__VA_ARGS__)
typedef long long ll;typedef unsigned long long ull;
template<typename A,typename B>inline char SMAX(A&a,const B&b){return a<b?a=b,1:0;}
template<typename A,typename B>inline char SMIN(A&a,const B&b){return a>b?a=b,1:0;}
const int N=200000+7;
int n,m,T,p1,p2,a[N],x,y,q[N],tl,lp[N],rp[N];
struct Node{int lc,rc,lps;ll val,add;}t[N*50];int RT[N],nod;//错误笔记:这里不是单调修改,所以仅仅开LOG被是不够的
inline void Insert(int &o,int L,int R,int l,int r,int k){
if(t[o].lps<T)t[++nod]=t[o],o=nod,t[o].lps=T;
if(l<=L&&R<=r)return (void)(t[o].add+=k,t[o].val+=(ll)k*(R-L+1));
int M=(L+R)>>1;if(l<=M)Insert(t[o].lc,L,M,l,r,k);if(r>M)Insert(t[o].rc,M+1,R,l,r,k);
t[o].val=t[t[o].lc].val+t[t[o].rc].val+t[o].add*(R-L+1);
}
inline ll Query(int o,int p,int L,int R,int l,int r,ll adv){
if(l<=L&&R<=r)return t[o].val-t[p].val+adv*(R-L+1);
int M=(L+R)>>1;if(r<=M)return Query(t[o].lc,t[p].lc,L,M,l,r,adv+t[o].add-t[p].add);else if(l>M)return Query(t[o].rc,t[p].rc,M+1,R,l,r,adv+t[o].add-t[p].add);
else return Query(t[o].lc,t[p].lc,L,M,l,r,adv+t[o].add-t[p].add)+Query(t[o].rc,t[p].rc,M+1,R,l,r,adv+t[o].add-t[p].add);
}
struct Pair{int x,y,w;};std::vector<Pair>g[N];
inline void Preprocess(){
REP(i,1,n){
while(tl&&a[q[tl]]<a[i])--tl;
q[++tl]=i;lp[i]=q[tl-1];
}q[tl=0]=n+1;PER(i,n,1){
while(tl&&a[q[tl]]<a[i])--tl;
q[++tl]=i;rp[i]=q[tl-1];
if(i<n)g[i].push_back(Pair{i+1,i+1,p1});
if(lp[i]&&rp[i]<=n)g[rp[i]].push_back(Pair{lp[i],lp[i],p1});
if(rp[i]<=n&&i-1>=lp[i]+1)g[rp[i]].push_back(Pair{lp[i]+1,i-1,p2});
if(lp[i]&&i+1<=rp[i]-1)g[lp[i]].push_back(Pair{i+1,rp[i]-1,p2});
}
REP(i,1,n){
T=i;RT[i]=RT[i-1];int len=g[i].size();
REP(j,0,len-1)Insert(RT[i],1,n,g[i][j].x,g[i][j].y,g[i][j].w);
}
}
int main(){
read(n);read(m),read(p1),read(p2);
REP(i,1,n)read(a[i]);
Preprocess();
REP(i,1,m){
read(x),read(y);
printf("%lld\n",Query(RT[y],RT[x-1],1,n,x,y,0));
}return flush(),0;
}
[BZOJ4826] [HNOI2017] 影魔 单调栈 主席树的更多相关文章
- BZOJ 4826: [Hnoi2017]影魔 单调栈 主席树
https://www.lydsy.com/JudgeOnline/problem.php?id=4826 年少不知空间贵,相顾mle空流泪. 和上一道主席树求的东西差不多,求两种对 1. max(a ...
- 【bzoj4826】[Hnoi2017]影魔 单调栈+可持久化线段树
题目描述 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己 ...
- 【BZOJ4826】[Hnoi2017]影魔 单调栈+扫描线
[BZOJ4826][Hnoi2017]影魔 Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝 ...
- BZOJ 4826: [Hnoi2017]影魔 单调栈+可持久化线段树
Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样 的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个 ...
- [BZOJ4826][HNOI2017]影魔 可持久化线段树
链接 题意:给你 \(1\) 到 \(n\) 的排列 \(k_1,k_2,\dots,k_n\) ,对 \(i,j (i<j)\)来说,若不存在 \(k_s (i<s<j)\) 大于 ...
- 洛谷P4198 楼房重建 单调栈+线段树
正解:单调栈+线段树 解题报告: 传送门! 首先考虑不修改的话就是个单调栈板子题昂,这个就是 然后这题的话,,,我怎么记得之前考试好像有次考到了类似的题目昂,,,?反正我总觉着这方法似曾相识的样子,, ...
- 2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树)
2018宁夏邀请赛 L Continuous Intervals(单调栈+线段树) 传送门:https://nanti.jisuanke.com/t/41296 题意: 给一个数列A 问在数列A中有多 ...
- [bzoj4826][Hnoi2017]影魔_单调栈_主席树
影魔 bzoj-4826 Hnoi-2017 题目大意:给定一个$n$个数的序列$a$,求满足一下情况的点对个数: 注释:$1\le n,m\le 2\cdot 10^5$,$1\le p1,p2\l ...
- 【ZJOI2017 Round2练习&BZOJ4826】D1T2 sf(主席树,单调栈)
题意: 思路:From http://blog.csdn.net/neither_nor/article/details/70211150 对每个点i,单调栈求出左边和右边第一个大于i的位置,记为l[ ...
随机推荐
- 循序渐进实现仿QQ界面(一):园角矩形与双缓冲贴图窗口
印象里仿QQ界面的程序应该有很多,搜了一下,虽然出来一大堆,排除了重复的,却只有两三个,没我想象的好.经常看到CSDN上有人问,QQ这个功能怎么实现,那个界面怎么实现,归纳了一下,决定写这么一个仿QQ ...
- [CSP-S模拟测试]:凤凰院凶真(LCIS)
题目描述 $\alpha$世界线.凤凰院凶真创立了反抗$SERN$统治的组织“瓦尔基里”.为了脱离$\alpha$线,他需要制作一个世界线变动率测量仪.测量一个世界线相对于另一个世界线的变动率,实质上 ...
- Spring中@Async-异步处理
在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3.x之后, ...
- 30个有关Python的小技巧,给程序员的 30 个基本 Python 贴士与技巧
30个有关Python的小技巧 2013/07/04 · Python, 开发 · 4 评论 · Python 分享到: 66 本文由 伯乐在线 - Kevin Sun 翻译.未经许可,禁止转载!英文 ...
- svn 中的add 和commit命令有何区别
add 功能:向文件拷贝所在的文件夹中添加新的文件,并作出标识,是新添加的,下一步提交时将一并提交到Subversion版本库中去.简单的说就是将一新文件加入svn,你添加再提交后该文件就进入subv ...
- DG-V$MANAGED_STANDBY视图
V$MANAGED_STANDBY displays current status information for some Oracle Database processes related to ...
- 结合Pool进程池进程,实现进程之间的通讯,稍微复杂的运用
#进程池中的Queue """ 如果要用Pool创建进程,就需要multiprocessing.Manager()中的Queue() 而不是multiprocessing ...
- 继承Process类,计算累加和以及阶乘
#定义一个类 继承Process类 from multiprocessing import Process import os class Download(Process): def __init_ ...
- 洛谷P2865 [USACO06NOV]路障Roadblocks——次短路
给一手链接 https://www.luogu.com.cn/problem/P2865 这道题其实就是在维护最短路的时候维护一下次短路就okay了 #include<cstdio> #i ...
- JavaScript Is or isNot
读书笔记,简化代码--不对外公布,只是做笔记使用. var superman = { name: "Superman", strength: "Super", ...