题目描述

奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n。第 i 个灵魂的战斗力为 ki ,灵魂们以点对的形式为影魔提供攻击力。对于灵魂对 i,j (i<j) 来说,若不存在 ks (i<s<j) 大于 ki 或者 kj ,则会为影魔提供 p1的攻击力。另一种情况,令 c 为 ki+1, ki+2, ……, kj -1 的最大值,若 c 满足:ki < c < kj ,或者 kj < c < ki ,则会为影魔提供 p2的攻击力,当这样的 c 不存在时,自然不会提供这 p2的攻击力;其他情况的点对,均不会为影魔提供攻击力。
影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任意一段区间 [a,b],位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑所有满足 a≤i<j≤b 的灵魂对 i,j 提供的攻击力之和。
顺带一提,灵魂的战斗力组成一个 1 到 n 的排列:k1, k2 ,⋯,kn。

输入格式

第一行四个整数 n,m,p1,p2。
第二行 n 个整数 k1,k2,⋯,kn。
接下来 mm 行,每行两个数 a,ba,b,表示询问区间 [a,b][a,b] 中的灵魂对会为影魔提供多少攻击力。

输出格式

共输出 m 行,每行一个答案,依次对应 m 个询问。

输入输出样例

输入
10 5 2 3
7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5
输出
30
39
4
13
16

说明/提示

对于 30% 的数据,1≤n,m≤500。
另有 30% 的数据,p1 = 2p。
对于 100% 的数据,1≤n,m≤200000,1≤p1,p2≤1000。

题目分析

要考虑这两种贡献,我们可以分成两种情况:对于区间[l,r]
1)r-l==1时,也就是说区间(l,r)为空,此时k[l]和k[r]一定是大于 (l,r) 中的所有数的,因此一点可以提供p1的贡献

2)r-l>1时,(l,r) 中一定有唯一的最大值,我们设最大值在 i 处,我们可以枚举所有的 i ,看看它会对那些区间产生影响。
我们设l[i]为i左边第一个大于k[i]的数,r[i]为i右边第一个大于k[i]的数。这两个数组我们可以用单调栈直接求出来。

  1. 若i为 (l,r) 中的最大值,并且区间 [l,r] 产生了p1的贡献,那么说明 l[i]=l,r[i]=r。因为如果 l > l[i] ,那么说明 k[l] < k[i],因此该区间无法提供p1的贡献;而如果 l < l[i],那么说明 k[l[i]] > l[i],这样i就不是(l,r)的最大值了,也无法提供p1的贡献。右端点同理。
  2. 若i为 (l,r) 中的最大值,并且区间 [l,r] 产生了p2的贡献,那么有两种情况:
    (1)l=l[i],r<r[i],也就是说形成了 k[l] > k[i] > k[r] 的形式,那么此时对于i来说,区间 [l, [i+1,r]] 都可以产生p2的贡献。
    (2)l>l[i],r=r[i],也就是说形成了 k[r] > k[i] > k[l] 的形式,那么此时对于i来说,区间 [[l,i-1], r] 都可以产生p2的贡献。

综上,对于区间l[i]到r[i]有p1的贡献.
对于左端点在l[i]+1到i-1,右端点为R[i]的区间有p2的贡献.
对于左端点为l[i],右端点为i+1到r[i]-1的区间也有p2的贡献.

然后我们可以从左到右进行枚举,
对于情况1来说,当我们扫到 r[i] 时,更新l[i]的贡献。
对于情况2.1来说,当我们扫到 l[i] 时,更新区间 [i+1,r[i]-1] 的贡献。
对于情况2.2来说,我们在扫到 r[i] 时,更新区间 [l[i]+1,i-1] 的贡献。

对于区间的加数与求和操作,我们用树状数组即可完成。

代码如下
#include <iostream>
#include <cmath>
#include <cstdio>
#include <set>
#include <unordered_set>
#include <string>
#include <cstring>
#include <map>
#include <unordered_map>
#include <algorithm>
#include <stack>
#include <queue>
#include <bitset>
#define LL long long
#define PII pair<int,int>
#define PDD pair<double,double>
#define x first
#define y second
using namespace std;
const int N=4e5+5,INF=0x3f3f3f3f;
struct Node{                //记录查询区间int l,r,x,id,v;bool operator< (const Node &a)const{ return x<a.x; }
}a[N],b[N];
int k[N];                   //题目中的k[i]数组
int st[N],top;              //单调栈
int l[N],r[N];
LL tr1[N],tr2[N],ans[N];    //树状数组与答案数组
int lowbit(int x)           //以下三个函数是树状数组的模板函数
{return x&-x;
}
void add(int x,int c)
{for(int i=x;i<N;i+=lowbit(i))tr1[i]+=c,tr2[i]+=(LL)c*x;
}
LL sum(int x)
{LL res=0;for(int i=x;i;i-=lowbit(i))res+=(LL)tr1[i]*(x+1)-tr2[i];return res;
}
int main()
{int n,m,p1,p2;scanf("%d%d%d%d",&n,&m,&p1,&p2);k[0]=k[n+1]=n+1; top=1;               //在0和n+1位置放两个哨兵,防止预处理l[i]和r[i]时出现越界for(int i=1;i<=n;i++) scanf("%d",&k[i]);for(int i=1;i<=n+1;i++)             //预处理l[i]和r[i]{while(k[st[top]]<k[i]) r[st[top]]=i,top--;l[i]=st[top];st[++top]=i;}for(int i=1;i<=m;i++)         //离线算法,用a[i]记录询问区间{int l,r;scanf("%d%d",&l,&r);ans[i]=(r-l)*p1;       //对于区间[l,r]来说,可以贡献r-l个长度为2的区间a[i]={l,r,l-1,i,-1};a[i+m]={l,r,r,i,1};}sort(a+1,a+1+m*2);int tot=0;for(int i=1;i<=n;i++)     //用b[]记录贡献区间,扫到x时给[l,r]都加v{if(1<=l[i]&&r[i]<=n) b[++tot]={l[i],l[i],r[i],0,p1};if(1<=l[i]&&r[i]>i+1) b[++tot]={i+1,r[i]-1,l[i],0,p2};if(i-1>l[i]&&r[i]<=n) b[++tot]={l[i]+1,i-1,r[i],0,p2};}sort(b+1,b+1+tot);int n1=1,n2=1;while(!a[n1].x) n1++;               //过滤掉x为0的a[]for(int i=1;n1<=m*2&&i<=n;i++){while(n2<=tot&&b[n2].x==i)      //当扫描到b[].x时,加上该贡献{add(b[n2].l,b[n2].v);     //给[l,r]都加上vadd(b[n2].r+1,-b[n2].v);n2++; }while(n1<=m*2&&a[n1].x==i)      //当扫描到a[].x时,算出该询问{ans[a[n1].id]+=a[n1].v*(sum(a[n1].r)-sum(a[n1].l-1));n1++;}}for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);       //输出答案return 0;
}

P3722 [AH2017/HNOI2017]影魔(树状数组)相关推荐

  1. 洛谷P3722 [AH2017/HNOI2017]影魔

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

  2. [AH2017/HNOI2017]影魔

    P3722 [AH2017/HNOI2017]影魔 题解: 法一: [bzoj4826][HNOI2017]影魔 直接转化成区间内单点的贡献, 分开p1,p2考虑 而min(ai,aj),max(ai ...

  3. [CSP-S模拟测试]:影魔(树状数组+线段树合并)

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

  4. 洛谷 P5057 [CQOI2006]简单题(树状数组)

    嗯... 题目链接:https://www.luogu.org/problem/P5057 首先发现这道题中只有0和1,所以肯定与二进制有关.然后发现这道题需要支持区间更改和单点查询操作,所以首先想到 ...

  5. Color the ball(HDU1556)树状数组

    每次对区间内气球进行一次染色,求n次操作后后所有气球染色次数. 树状数组,上下区间更新都可以,差别不大. 1.对于[x,y]区间,对第x-1位减1,第y位加1,之后向上统计 #include<b ...

  6. 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

    [BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...

  7. Codeforces 629D Babaei and Birthday Cake(树状数组优化dp)

    题意: 线段树做法 分析: 因为每次都是在当前位置的前缀区间查询最大值,所以可以直接用树状数组优化.比线段树快了12ms~ 代码: #include<cstdio> #include< ...

  8. poj_3067 树状数组

    题目大意 左右两个竖排,左边竖排有N个点,从上到下依次标记为1,2,...N; 右边竖排有M个点,从上到下依次标记为1,2....M.现在从K条直线分别连接左边一个点和右边一个点,求这K条直线的交点个 ...

  9. hdu 1166 敌兵布阵(树状数组)

    题意:区间和 思路:树状数组 #include<iostream> #include<stdio.h> #include<string.h> using names ...

最新文章

  1. Centos7 下安装python3及卸载
  2. 一起谈.NET技术,页面片段缓存(二)
  3. Elasticsearch java客户端调用cat服务
  4. 图像处理(七)导向滤波磨皮
  5. github mac 添加 ssh_计算机专业MAC操作技巧(二)
  6. 拳王公社:从0-1只需掌握这3个重点​,网创再也不缺精准流量
  7. java读二进制bin文件内容_利用Java读取二进制文件示例详细解说
  8. -xdebug java8_多种高级debug方法,帮你更快定位问题
  9. python的ide怎么安装_python安装以及IDE的配置教程
  10. C# 电子白板软件开发
  11. LinkedIn应用开发系列(三) --认证Request token
  12. 获取Android手机短信中心号码
  13. 学习笔记15--车道线检测
  14. 2022-2027年中国OLED发光和传输材料市场规模现状及投资规划建议报告
  15. 光学系统像差的计算机模拟实验报告,RLE-ME01-光学系统像差测量实验-实验讲义要点.doc...
  16. 鸿蒙 电视盒子,目前最强的电视盒子:性价比最高的5款电视盒子
  17. [20190718]12c rman新特性 表恢复.txt
  18. VideoProc for Mac(全能影片处理软件)
  19. 【100个 Unity小知识点】☀️ | Unity 中怎样读取Excel文件
  20. 数据库触发器实例讲解

热门文章

  1. 怎么把php转变成word文档,表格怎么转换成word文档
  2. 理解和使用alsa配置-默认静音,必须先用amixer解除主音量和pcm音量的静音
  3. 无人机光电系统图像处理模块AVT22
  4. 微信小程序只允许触发一次点击事件(防止多次点击事件)
  5. 解决VMware虚拟机无法识别U盘问题
  6. 华为防火墙性能指标监控
  7. 超9成SCI论文发在国外!中文期刊到底差在哪?
  8. excel成本统计:如何进行区域筛选,多条件求和?
  9. 电子小制作:电烙铁恒温控制器
  10. JAVA 80行代码 写一个 万年历