题目背景

影魔,奈文摩尔,据说有着一个诗人的灵魂。 事实上,他吞噬的诗人灵魂早已成千上万。

千百年来,他收集了各式各样的灵魂,包括诗人、 牧师、 帝王、 乞丐、 奴隶、 罪人,当然,还有英雄。

题目描述

每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。

奈文摩尔有 n 个灵魂,他们在影魔宽广的体内可以排成一排,从左至右标号 1 到 n。第 i个灵魂的战斗力为 k[i],灵魂们以点对的形式为影魔提供攻击力,对于灵魂对 i, j(i<j)来说,若不存在 ks大 于 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]中的灵魂对会为影魔提供多少攻击力。

输出格式:

输出文件名为 sf.out

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

输入输出样例

输入样例#1:

10 5 2 3
7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5
输出样例#1:

30
39
4
13
16

说明

30%: 1<= n,m <= 500。

另 30%: p1=2*p2。

100%:1 <= n,m <= 200000; 1 <= p1,p2 <= 1000。

补上一个更好理解的方法:主席树

令L[i]为i前第一个比a[i]大的一位,R[i]为i后第一个比a[i]大的一位

1.每组(R[i],L[i])  (i,i+1)可以贡献p1
2.(L[i],j) (i+1<=j<=R[i]-1)  (R[i],j)(L[i]+1<=j<=i-1) 都可以贡献p2
把他们转化为点(c,p,l,r)表示p与[l,r]构成第c种贡献
按p排序后按顺序建主席树
查询时查询[l,r]线段树内[l,r]区间的和,再加上(i,i+1)的方案
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long lol;
struct ZYYS
{
int c,p,l,r;
}q[];
int pos,ch[][],root[],a[],sta[],top,n,m,lst[],nxt[],cnt;
lol sum[],lazy[],p1,p2;
bool cmp(ZYYS a,ZYYS b)
{
return a.p<b.p;
}
void update(int &rt,int l,int r,int L,int R,lol k,int last)
{
int x=rt;
if (rt<=last)
{
rt=++pos;
ch[rt][]=ch[x][];ch[rt][]=ch[x][];
sum[rt]=sum[x];
lazy[rt]=lazy[x];
}
if (l>=L&&r<=R)
{
sum[rt]+=(r-l+)*k;
lazy[rt]+=k;
return ;
}
int mid=(l+r)/;
if (L<=mid) update(ch[rt][],l,mid,L,R,k,last);
if (R>mid) update(ch[rt][],mid+,r,L,R,k,last);
sum[rt]=sum[ch[rt][]]+sum[ch[rt][]]+(r-l+)*lazy[rt];
}
lol query(int x,int y,int l,int r,int L,int R,lol la)
{
if (l>=L&&r<=R)
{
return sum[y]-sum[x]+la*(r-l+);
}
int mid=(l+r)/;
lol s=;
if (L<=mid) s+=query(ch[x][],ch[y][],l,mid,L,R,la+lazy[y]-lazy[x]);
if (R>mid) s+=query(ch[x][],ch[y][],mid+,r,L,R,la+lazy[y]-lazy[x]);
return s;
}
int main()
{int i,x,l,r,last=;
cin>>n>>m>>p1>>p2;
for (i=;i<=n;i++)
scanf("%d",&a[i]);
top=;
for (i=;i<=n;i++)
{
while (top&&a[sta[top]]<a[i]) top--;
lst[i]=sta[top];
top++;
sta[top]=i;
}
top=;
sta[]=n+;
for (i=n;i>=;i--)
{
while (top&&a[sta[top]]<a[i]) top--;
nxt[i]=sta[top];
top++;
sta[top]=i;
}
for (i=;i<=n;i++)
{
if (lst[i]&&nxt[i]<=n)
{
q[++cnt]=(ZYYS){,lst[i],nxt[i],nxt[i]};
q[++cnt]=(ZYYS){,nxt[i],lst[i],lst[i]};
}
if (lst[i]&&nxt[i]-i>)
q[++cnt]=(ZYYS){,lst[i],i+,nxt[i]-};
if (nxt[i]<=n&&i-lst[i]>)
q[++cnt]=(ZYYS){,nxt[i],lst[i]+,i-};
}
sort(q+,q+cnt+,cmp);
x=;
last=;
for (i=;i<=cnt;i++)
{
while (x<q[i].p) root[x+]=root[x],x++,last=pos;
if (q[i].c==)
update(root[x],,n,q[i].l,q[i].r,p1,last);
else update(root[x],,n,q[i].l,q[i].r,*p2,last);
}
while (x<n) root[x+]=root[x],x++;
for (i=;i<=m;i++)
{
scanf("%d%d",&l,&r);
printf("%lld\n",query(root[l-],root[r],,n,l,r,)/+(r-l)*p1);
}
}

线段树:

统计:
我们假设i和[i+1,R[i]-1]之间的数都可以搭配成p2的条件,然后我们就在线段树中把[i+1,R[i]-1]加上p2.
因为(i,R[i])在反方向算作了p2,所以应该+p1-p2,这样反向算时等价于只+p1
对于i和L[i],把数列和询问反转,在做一次相同操作
 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Ask
{
int l,r,id;
}q[];
int a[],aa[],n,m,stack[],R[];
long long c[],mark[],ans[],p1,p2;
bool cmp(Ask a,Ask b)
{
return a.l<b.l;
}
void pushup(int rt)
{
c[rt]=c[rt*]+c[rt*+];
}
void pushdown(int rt,int l,int r,int mid)
{
if (mark[rt])
{
mark[rt*]+=mark[rt];
mark[rt*+]+=mark[rt];
c[rt*]+=mark[rt]*(mid-l+);
c[rt*+]+=mark[rt]*(r-mid);
mark[rt]=;
}
}
void change(int rt,int l,int r,int L,int R,long long d)
{
if (l>=L&&r<=R)
{
mark[rt]+=d;
c[rt]+=(r-l+)*d;
return;
}
pushdown(rt,l,r,(l+r)/);
int mid=(l+r)/;
if (L<=mid) change(rt*,l,mid,L,R,d);
if (R>mid) change(rt*+,mid+,r,L,R,d);
pushup(rt);
}
long long getsum(int rt,int l,int r,int L,int R)
{
if (l>=L&&r<=R)
{
return c[rt];
}
int mid=(l+r)/;
pushdown(rt,l,r,mid);
long long s=;
if (L<=mid) s+=getsum(rt*,l,mid,L,R);
if (R>mid) s+=getsum(rt*+,mid+,r,L,R);
pushup(rt);
return s;
}
void work()
{int i;
memset(c,,sizeof(c));
memset(mark,,sizeof(mark));
sort(q+,q+m+,cmp);
int top=;
stack[]=n+;
for (i=n;i>=;i--)
{
while (top&&a[i]>=a[stack[top]]) top--;
R[i]=stack[top];
stack[++top]=i;
}
top=m;
for (i=n;i>=;i--)
{
if (i+<=R[i]-)
change(,,n,i+,R[i]-,p2);
change(,,n,R[i],R[i],p1-p2);
while (top&&q[top].l==i)
ans[q[top].id]+=getsum(,,n,,q[top].r),top--;
}
}
void rev()
{int i;
for (i=;i<=n;i++)
aa[i]=a[n-i+];
for (i=;i<=n;i++)
a[i]=aa[i];
}
int main()
{int i;
cin>>n>>m>>p1>>p2;
for (i=;i<=n;i++)
{
scanf("%d",&a[i]);
}
for (i=;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
work();
rev();
for (i=;i<=m;i++)
q[i].l=n+-q[i].l,q[i].r=n+-q[i].r,swap(q[i].l,q[i].r);
work();
for (i=;i<=m;i++)
printf("%lld\n",ans[i]);
}

庆祝FGO第一/二个SSR

[AH/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. HNOI2017影魔

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

随机推荐

  1. C语言作业第二次总结

    1.作业亮点 1.1作业整体概况 本次作业全体同学能够按时完成作业,且大部分同学的作业体现了自己的思路和方法,具备了一定变成能力. 1.2推荐博客 林岳-代码注释清晰,详细.->博文 王艺斌-算 ...

  2. alpha-咸鱼冲刺day8-紫仪

    总汇链接 一,合照 emmmmm.自然还是没有的. 二,项目燃尽图 三,项目进展 正在进行页面整合.然后还有注册跟登陆的功能完善-- 四,问题困难 数据流程大概是搞定了.不过语法不是很熟悉,然后还有各 ...

  3. Linux下I/O多路转接之epoll(绝对经典)

    epoll 关于Linux下I/O多路转接之epoll函数,什么返回值,什么参数,我不想再多的解释,您不想移驾,我给你移来: http://blog.csdn.net/colder2008/artic ...

  4. 使用Spark MLlib进行情感分析

    使用Spark MLlib进行情感分析             使用Spark MLlib进行情感分析 一.实验说明 在当今这个互联网时代,人们对于各种事情的舆论观点都散布在各种社交网络平台或新闻提要 ...

  5. Hibernate之HQL

    SQL语句的DML操作不外乎:增,删,改,查 增加 :  save(),persist() 删除 :   delete() 改动 :   update() 查询  :  get() ,load() 其 ...

  6. Tomcat 8项目无法启动,无报错

    作者:chszs,转载需注明.博客主页:http://blog.csdn.net/chszs Tomcat 8启动很慢,且日志上无任何错误,在日志中查看到如下信息: Log4j:[2015-10-29 ...

  7. pdf解析与结构化提取

    #PDF解析与结构化提取##PDF解析对于PDF文档,我们选择用PDFMiner对其进行解析,得到文本.###PDFMinerPDFMiner使用了一种称作lazy parsing的策略,只在需要的时 ...

  8. SpringCloud是否值得引入?

    中小型互联网公司微服务实践-经验和教训 http://xujin.org/sc/sc-zq/#more Spring Cloud在国内中小型公司能用起来吗?https://mp.weixin.qq.c ...

  9. 京东2019春招Java工程师编程题题解

    生成回文串 题目描述 对于一个字符串,从前开始读和从后开始读是一样的,我们就称这个字符串是回文串. 例如"ABCBA","AA","A"是回 ...

  10. Python基础数据类型之int、bool、str

    数据类型:int  bool  str  list  元祖  dict  集合 int:整数型,用于各种数学运算. bool:只有两种,True和False,用户判断. str:存储少量数据,进行操作 ...