题链:

http://www.lydsy.com/JudgeOnline/problem.php?id=4826

题解:

主席树,单调栈

以前还没做过这种维护信息的题,感觉好奇妙。

每对相邻的两个数所贡献的 P1 就直接在最后加入答案就好了,
以下是处理存在 s (i<s<j)的情况。
首先用单调栈维护出 L[i], R[i]分别表示 i 点左边和右边第一个值大于 K[i]的位置。
然后不难发现,如果对应的 L[i] 或 R[i] 存在于 K 数组中,那么
点对 (L[i],R[i]) 可以贡献一个 P1
点对 (L[i],i+1~R[i]-1) 每个都可以贡献一个 P2
点对 (L[i]+1~i-1,R[i]) 每个都可以贡献一个 P2
然后把这些点对看成是平面上的点,
那么就可以用两个主席树来处理好信息后,然后在线查询。
怎么维护呢?
注意到我们需要的是对平面的某个点或者是某条线段上的点进行值的累加。
且线段又只存在平行于 x 轴的和平行于 y 轴的。
所以两个主席树分别对应着维护平行着某一轴的线段的信息就好了。

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define ll long long
#define filein(x) freopen(#x".in","r",stdin)
#define fileout(x) freopen(#x".out","w",stdout)
using namespace std;
const int MAXN=2e5+5;
int A[MAXN];
int N,M,P1,P2;
struct List{
int L[MAXN*2],R[MAXN*2],W[MAXN*2],Nxt[MAXN*2],Head[MAXN],lnt;
void Reset(){
lnt=2; memset(Head,0,sizeof(Head));
}
void Add(int p,int l,int r,int w){
L[lnt]=l; R[lnt]=r; W[lnt]=w;
Nxt[lnt]=Head[p]; Head[p]=lnt++;
}
}l1,l2;
struct CMT{
#define len ((r<ar?r:ar)-(l>al?l:al)+1)
int rt[MAXN],ls[MAXN*50],rs[MAXN*50],sz; ll Sum[MAXN*50],Add[MAXN*50];
void Insert(int &u,int l,int r,int al,int ar,int w){
++sz; ls[sz]=ls[u]; rs[sz]=rs[u];
Sum[sz]=Sum[u]; Add[sz]=Add[u]; u=sz;
if(al<=l&&r<=ar){
Add[u]+=w; Sum[u]+=len*w;
return;
}
int mid=(l+r)>>1; Sum[u]+=len*w;
if(al<=mid) Insert(ls[u],l,mid,al,ar,w);
if(mid<ar) Insert(rs[u],mid+1,r,al,ar,w);
}
ll Query(int v,int u,int l,int r,int al,int ar){
if(!u) return 0;
if(al<=l&&r<=ar) return Sum[u]-Sum[v];
int mid=(l+r)>>1; ll ret=(Add[u]-Add[v])*(len);
if(al<=mid) ret+=Query(ls[v],ls[u],l,mid,al,ar);
if(mid<ar) ret+=Query(rs[v],rs[u],mid+1,r,al,ar);
return ret;
}
void Build(const List &li){
for(int p=1;p<=N;p++){
rt[p]=rt[p-1];
for(int i=li.Head[p],l,r,w;i;i=li.Nxt[i]){
l=li.L[i]; r=li.R[i]; w=li.W[i];
Insert(rt[p],1,N,l,r,w);
}
}
}
ll Query(int l,int r){
return Query(rt[l-1],rt[r],1,N,l,r);
}
#undef len
}T1,T2;
char gc(){
return getchar();
static char s[MAXN];
static int bit=200000,p,len;
if(p>=len) len=fread(s,1,bit,stdin),s[len]=EOF,p=0;
return s[p++];
}
void read(int &x){
static int f; static char ch;
x=0; f=1; ch=gc();
while(ch<'0'||'9'<ch){if(ch=='-') f=-1;ch=gc();}
while('0'<=ch&&ch<='9'){x=x*10+ch-'0'; ch=gc();}
x=x*f;
}
void pre(){
static int L[MAXN],R[MAXN],stk[MAXN],stp[MAXN],top=0;
for(int i=1;i<=N;i++){
while(top&&A[i]>stk[top]) R[stp[top]]=i,top--;
L[i]=stp[top]; top++;
stk[top]=A[i]; stp[top]=i;
}
while(top) R[stp[top--]]=N+1;
for(int i=1;i<=N;i++){
if(1<=L[i]&&R[i]<=N) l1.Add(L[i],R[i],R[i],P1);
if(1<=L[i]&&i+1<=R[i]-1) l1.Add(L[i],i+1,R[i]-1,P2);
if(L[i]+1<=i-1&&R[i]<=N) l2.Add(R[i],L[i]+1,i-1,P2);
}
T1.Build(l1); T2.Build(l2);
}
int main(){
//filein(4826);
l1.Reset(); l2.Reset();
read(N); read(M); read(P1); read(P2);
for(int i=1;i<=N;i++) read(A[i]);
pre();
for(int i=1,l,r;i<=M;i++){
read(l); read(r);
printf("%lld\n",T1.Query(l,r)+T2.Query(l,r)+1ll*(r-l)*P1);
}
return 0;
}

●BZOJ 4826 [Hnoi2017]影魔的更多相关文章

  1. bzoj 4826: [Hnoi2017]影魔 [主席树 单调栈]

    4826: [Hnoi2017]影魔 题意:一个排列,点对\((i,j)\),\(p=max(i+1,j-1)\),若\(p<a_i,a_j\)贡献p1,若\(p\)在\(a_1,a_2\)之间 ...

  2. BZOJ:4826: [Hnoi2017]影魔

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

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

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

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

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

  5. BZOJ 4826 [Hnoi2017]影魔 ——扫描线 单调栈

    首先用单调栈和扫描线处理出每一个数左面最近的比他大的数在$l[i]$,右面最近的比他大的数$r[i]$. 然后就可以考虑每种贡献是在什么时候产生的. 1.$(l[i],r[i])$产生$p1$的贡献 ...

  6. bzoj 4826: [Hnoi2017]影魔【单调栈+树状数组+扫描线】

    参考:https://www.cnblogs.com/lcf-2000/p/6789680.html 这是一个相对码量少的做法,用到了区间修改区间查询的树状数组,详见:www.cnblogs.com/ ...

  7. 4826: [Hnoi2017]影魔

    4826: [Hnoi2017]影魔 https://lydsy.com/JudgeOnline/problem.php?id=4826 分析: 莫队+单调栈+st表. 考虑如何O(1)加入一个点,删 ...

  8. [BZOJ4826][HNOI2017]影魔(主席树)

    4826: [Hnoi2017]影魔 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 669  Solved: 384[Submit][Status][ ...

  9. 【LG3722】[HNOI2017]影魔

    [LG3722][HNOI2017]影魔 题面 洛谷 题解 先使用单调栈求出\(i\)左边第一个比\(i\)大的位置\(lp_i\),和右边第一个比\(i\)大的位置\(rp_i\). 考虑\(i\) ...

随机推荐

  1. bisect 二分查找

    先说明的是,使用这个模块的函数前先确保操作的列表是已排序的. 先看看 insort  函数: 其插入的结果是不会影响原有的排序. 再看看 bisect  函数: 其目的在于查找该数值将会插入的位置并返 ...

  2. Scrum 冲刺 第二日

    Scrum 冲刺 第二日 目录 要求 项目链接 燃尽图 问题 今日任务 明日计划 成员贡献量 要求 各个成员今日完成的任务(如果完成的任务为开发或测试任务,需给出对应的Github代码签入记录截图:如 ...

  3. Linux下关闭Tomcat残留线程

    ps -ef | grep tomcat kill -9 {pid}

  4. bzoj千题计划288:bzoj1876: [SDOI2009]SuperGCD

    http://www.lydsy.com/JudgeOnline/problem.php?id=1876 高精压位GCD 对于  GCD(a, b)  a>b 若 a 为奇数,b 为偶数,GCD ...

  5. python小练习之一

    下面的练习本身不难,比如打印1到10,计算1+2+3+...+100 ,最后一个是计算 1-2+3-4...-100 用了类的方法实现 用了列表生成器 用"高级"一丢丢的写法来实现 ...

  6. Linux入门(1)_VMware和系统分区和系统安装和远程登陆管理

    1 VMware的安装和使用 注意有 快照 和 克隆 的功能. 快照相当于建立一个 系统还原点, 可以随时恢复到原来状态. 克隆功能可以复制一个和当前一样的系统,并可以选择链接安装,只使用很少的空间就 ...

  7. egg.js 的优缺点

    egg.js 的优缺点 优点 所有的 web开发的点都考虑到了 agent 很有特色 文件夹规划到位 扩展能力优秀 缺点 最大的问题在于: 使用 loader 加载之后,失去了代码提示的能力 监控和运 ...

  8. 链家2018春招Java工程师编程题题解

    Light 题目描述 在小红家里面,有n组开关,触摸每个开关,可以使得一组灯泡点亮.现在问你,使用这n组开关,最多能够使得多少个灯泡点亮呢? 输入 第一行一个n,表示有n组开关.接下来n行,每行第一个 ...

  9. jq中的表单验证插件------jquery.validate

    今天我们来说一下表单验证,有人说我们在进行表单验证的时候使用正则来验证是非常麻烦的,现在我来给大家介绍一下表单验证的插件:jquery.validate.min.js 它是与jquery一起结合用来使 ...

  10. Docker:云栖社区开源论题及Spark开源论题

    https://yq.aliyun.com/topic/78?spm=5176.8290451.656547.7.rMYhAF https://yq.aliyun.com/activity/155?u ...