题目描述

影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。
每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。
奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n。第 i 个灵魂的战斗力为 k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 i,j(i<j)来说,若不存在 k[s](i<s<j)大于 k[i]或者 k[j],则会为影魔提供 p1 的攻击力(可理解为:当 j=i+1 时,因为不存在满足 i<s<j 的 s,从而 k[s]不存在,这时提供 p1 的攻击力;当 j>i+1 时,若 max{k[s]|i<s<j}<=min{k[i],k[j]} ,则提供 p1 的攻击力);另一种情况,令 c 为 k[i+1],k[i+2],k[i+3]……k[j-1]的最大值,若 c 满足:k[i]<c<k[j],或者 k[j]<c<k[i],则会为影魔提供 p2 的攻击力,当这样的 c 不存在时,自然不会提供这 p2 的攻击力;其他情况的点对,均不会为影魔提供攻击力。
影魔的挚友噬魂鬼在一天造访影魔体内时被这些灵魂吸引住了,他想知道,对于任意一段区间[a,b],1<=a<b<=n,位于这些区间中的灵魂对会为影魔提供多少攻击力,即考虑所有满足 a<=i<j<=b 的灵魂对 i,j 提供的攻击力之和。
顺带一提,灵魂的战斗力组成一个 1 到 n 的排列:k[1],k[2],…,k[n]。

输入

输入文件名为 sf.in。
第一行 n,m,p1,p2
第二行 n 个数:k[1],k[2],…,k[n]
接下来 m 行,每行两个数 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=2*p2。
100%:1 <= n,m <= 200000;1 <= p1,p2 <= 1000。 
 
题解:
首先满足答案的条件很容易想,但一直不会打主席树,所以不知道怎么统计,今天学到了线段树解法.
设R[i]为i之后大于a[i]的第一个数的位置.L[i]为i之前大于a[i]的第一个数的位置.
容易想到:
1.每组[i,L[i]] [R[i],i] [i,i+1]可以贡献p1
2.[L[i],j] (i+1<=j<=R[i]-1)  [j,R[i]](L[i]+1<=j<=i-1) 都可以贡献p2
然后就是统计:
这里都是考虑i作为有p2贡献的区间中,两端点中较大的一个.
我们假设i和[i+1,R[i]-1]之间的数都可以搭配成p2的条件,然后我们就在线段树中把[i+1,R[i]-1]加上p2.
但是并不一定满足p2的条件 ,我们先不考虑,
明显的:在i作为较大的一方时,i和R[i]不可以形成p2的形式,但是肯定可以产生p1的贡献,所以加上p1减去p2,使得之前不合法的计算都抵消了.
然后再反转数组.
求出i和L[i]搭配的答案.
 
程序流程就是:
1.i从n到1枚举 每一次把[i+1,R[i]-1]加上p2,并且把R[i]处加上p1-p2.
2.L端点在i的询问就+=[1,R]的和  R为询问的端点.
3.反转数组和询问 进行相同操作.
 
代码不过100行:
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=;
int gi(){
int str=;char ch=getchar();
while(ch>'' || ch<'')ch=getchar();
while(ch>='' && ch<='')str=str*+ch-'',ch=getchar();
return str;
}
int L[N],R[N],n,m,p1,p2,a[N],q[N];
ll Tree[N*],mark[N*],ans[N];
struct AKK{
int id,l,r;
}ques[N];
#define ls (node<<1)
#define rs (node<<1|1)
void pushdown(int node,int l,int r)
{
if(!mark[node])return ;
int sizels=((l+r)>>)-l+,sizers=r-((l+r)>>);
Tree[ls]+=mark[node]*sizels;Tree[rs]+=mark[node]*sizers;
mark[ls]+=mark[node];mark[rs]+=mark[node];
mark[node]=;
}
void updata(int node){Tree[node]=Tree[ls]+Tree[rs];}
void change(int l,int r,int node,int sa,int se,int ad)
{
if(r<sa || l>se)return ;
if(sa<=l && r<=se)
{
Tree[node]+=(ll)ad*(r-l+);mark[node]+=ad;
return ;
}
pushdown(node,l,r);
int mid=(l+r)>>;
change(l,mid,ls,sa,se,ad);
change(mid+,r,rs,sa,se,ad);
updata(node);
}
ll getsum(int l,int r,int node,int sa,int se)
{
if(r<sa || l>se)return ;
if(sa<=l && r<=se)return Tree[node];
pushdown(node,l,r);
int mid=(l+r)>>;
return getsum(l,mid,ls,sa,se)+getsum(mid+,r,rs,sa,se);
updata(node);
}
void pf()
{
int r=;
q[r]=n+;
for(int i=n;i>=;i--)
{
while(r> && a[i]>=a[q[r]])r--;
R[i]=q[r];
q[++r]=i;
}
}
void work()
{
pf();
int k=m;
for(int i=n;i>=;i--)
{
if(i+<=R[i]-)
change(,n+,,i+,R[i]-,p2);change(,n+,,R[i],R[i],p1-p2);
while(k> && ques[k].l==i)ans[ques[k].id]+=getsum(,n+,,,ques[k].r),k--;
}
}
void Clear(){memset(Tree,,sizeof(Tree));memset(mark,,sizeof(mark));}
bool comp(const AKK &p,const AKK &qq){return p.l<qq.l;}
int main()
{
n=gi();m=gi();p1=gi();p2=gi();
for(int i=; i<=n; i++)a[i]=gi();
for(int i=;i<=m;i++)ques[i].l=gi(),ques[i].r=gi(),ques[i].id=i;
sort(ques+,ques+m+,comp);
work();
for(int i=;i<=m;i++)ques[i].l=n+-ques[i].l,ques[i].r=n+-ques[i].r,swap(ques[i].l,ques[i].r);
reverse(a+,a+n+);
sort(ques+,ques+m+,comp);
Clear();
work();
for(int i=;i<=m;i++)printf("%lld\n",ans[i]);
return ;
}

【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. 4826: [Hnoi2017]影魔

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

  3. 【LG3722】[HNOI2017]影魔

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

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

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

  5. 【BZOJ4826】[Hnoi2017]影魔 单调栈+扫描线

    [BZOJ4826][Hnoi2017]影魔 Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝 ...

  6. [bzoj4826][Hnoi2017]影魔_单调栈_主席树

    影魔 bzoj-4826 Hnoi-2017 题目大意:给定一个$n$个数的序列$a$,求满足一下情况的点对个数: 注释:$1\le n,m\le 2\cdot 10^5$,$1\le p1,p2\l ...

  7. bzoj4826 [Hnoi2017]影魔

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

  8. BZOJ:4826: [Hnoi2017]影魔

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

  9. [AH/HNOI2017]影魔

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

  10. HNOI2017影魔

    影魔 这么简单的方法尽然想不到,我是真的菜 对每个点,用单调栈的方式处理出他左右第一个比他大的数的位置,你可以把\(0\)和\(n+1\)设成\(inf\). 显然对于每对\(lef[i]\)和\(r ...

随机推荐

  1. Beta版本敏捷冲刺每日报告——Day3

    1.情况简述 Beta阶段第三次Scrum Meeting 敏捷开发起止时间 2017.11.4 08:00 -- 2017.11.4 22:00 讨论时间地点 2017.11.4晚9:00,软工所实 ...

  2. 团队作业7——第二次项目冲刺(Beta版本)

    Deadline: 2017-12-10 23:00PM,以博客发表日期为准.   评分基准: 按时交 - 有分,检查的项目包括后文的三个方面 冲刺计划安排(单独1篇博客) 七天的敏捷冲刺(每两天发布 ...

  3. Java暑期作业

    一.假期观影笔记--<熔炉> 影片<熔炉>是根据发生在韩国光州聋哑学校里的真实事件而改编.影片讲述的是在一所聋哑儿童学校里,校长.教务以及老师披着慈善的华丽外衣对学校中的多名未 ...

  4. mvc架构模式概念

    MVC模式是"Model-View-Controller"的缩写,中文翻译为"模式-视图-控制器".MVC应用程序总是由这三个部分组成.Event(事件)导致C ...

  5. 关于GPUImage的导入

    对于GPUImage的使用方面,GitHub上已经非常详细了,就不一一赘述了,但是对于项目的导入来说,最好的方式是 1.下载GPUImage并解压 2.打开压缩包后如图 3.打开终端,cd到此目录 4 ...

  6. Linux命令及lamp搭建

    单纯属于Linux的命令:1.强制卸载有依赖关系的软件包: rpm -e httpd-2.2.15-26.el6.x86_64 --nodeps(--nodeps表示无依赖)4.删除当前目录所有的文件 ...

  7. 安装CentOS7,连接mysql提示密码错误

    1.grep 'temporary password' /var/log/mysqld.log 如果上面命令没有查看到密码 2.修改my.cnf文件.在mysqld下加入skip-grant-tabl ...

  8. SQL SERVER 字符串按数字排序

    需求是这样的: 数据库表里面有一个字段类型是nvachar,存的值是数字和字符混合的,要实现先按数字排序,再按字母倒序. 思路: 考虑这个字段的值是否是有规律可循的,把要按数字排序的部分转换为数字,再 ...

  9. 写一个vue组件

    写一个vue组件 我下面写的是以.vue结尾的单文件组件的写法,是基于webpack构建的项目.如果还不知道怎么用webpack构建一个vue的工程的,可以移步到vue-cli. 一个完整的vue组件 ...

  10. Python学习之再议row_input

    再议raw_input birth = raw_input('birth: ') if birth < 2000: print '00前' else: print '00后' 运行结果: bir ...