[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[ ...
随机推荐
- 「THUPC 2017」机场 / Airport
https://loj.ac/problem/2403 题解 神仙题. 练习赛的时候想了个假建图. 正解太神仙了. 先把不合法情况判掉. 先对时间离散化,每个时间点开一个点. 然后把他们一次串起来,中 ...
- vue双向数据绑定v-model
1.双向数据绑定 <input v-model="msg" /> <template> <div id="app"> < ...
- JAVA数组的toString()方法不能直接输出数组内容?
问题描述:我定义了一个类,类名是Job,当我输出Job.toString()是可以按我重载的toString方法输出的,但是如果输出jobs[]这个数组时,只会输出[Lmodel.Job;@45e22 ...
- java后端发送请求并获取响应
URL wsUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection) wsUrl.openConnection(); conn. ...
- 用SPSS做时间序列
用SPSS做时间序列 关于时间序列,有好多软件可以支持分析,大家比较熟悉的可能是EVIEWS.SPSS.还有STATA,具体用啥软件,结果都是一样的,但是SPSS作为一款学习简单,使用容易的软件还是值 ...
- (转)Linux下编译安装log4cxx
Linux下编译安装log4cxx 一个项目的服务器端在Linux平台下,用到了开源日志库log4cxx,这个库是apache项目的一个子库.功能很不错.下面记录下它的编译和安装过程. log4cxx ...
- C#递归加载目录树
/// 获取目录管理信息集合 /// </summary> /// <returns></returns> public List<CatalogTree&g ...
- 用递归方法求n!
题目: 编写一个程序,输入n,求n!(用递归的方式实现). public class test { public static long fac(int n){ if(n<0){ return ...
- dp(01背包问题)
且说上一周的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励的时刻了! 小Ho现在手上有M张奖券,而奖品区有N件奖品,分别标号为1到N,其中第i件奖品需要need( ...
- wireshark自动化之tshark命令行
tshark是wireshark安装目录下命令行工具 使用tshark可以通过自动化方式调用wireshark tshark -a duration:30 抓包30秒-w cap.cap 保存为cap ...