【BZOJ4826】[Hnoi2017]影魔

Description

影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。千百年来,他收集了各式各样的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。奈文摩尔有 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]。

Input

第一行 n,m,p1,p2
第二行 n 个数:k[1],k[2],...,k[n]
接下来 m 行,每行两个数 a,b,表示询问区间[a,b]中的灵魂对会为影魔提供多少攻击力。
1 <= n,m <= 200000;1 <= p1,p2 <= 1000

Output

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

Sample Input

10 5 2 3
7 9 5 1 3 10 6 8 2 4
1 7
1 9
1 3
5 9
1 5

Sample Output

30
39
4
13
16

题解:用单调栈求出每个数左边和右边第一个比它大的数的位置,设其为l[i],r[i]。那么这样的点对:

(l[i],r[i]),(i,i+1)提供p1攻击力
(l[i]...i-1,r[i]),(l[i],i+1...r[i])提供p2攻击力

那么这就变成了在二维平面中,一些线段和点有权值,求矩形内的权值和。可以用扫描线解决(+区间修改树状数组)。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=200010;
typedef long long ll;
int n,m,n1,n2,m1,top;
int v[maxn],lm[maxn],rm[maxn],st[maxn];
ll p1,p2;
ll ans[maxn];
struct sag
{
int sx,sl,sr,sv;
}s1[maxn<<1],s2[maxn<<1];
struct QUERY
{
int qx,ql,qr,org,qv;
}q[maxn<<1];
struct BIT
{
ll s[maxn];
void init(){memset(s,0,sizeof(s));}
void updata(int x,ll val)
{
for(int i=x;i<=n;i+=i&-i) s[i]+=val;
}
ll query(int x)
{
ll ret=0;
for(int i=x;i;i-=i&-i) ret+=s[i];
return ret;
}
}sa,sb;
void modify(int x,ll val)
{
if(x<=0) return ;
sa.updata(x,val),sb.updata(x,val*x);
}
ll ask(int x)
{
return (sa.query(n)-sa.query(x))*x+sb.query(x);
}
int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
bool cmps(sag a,sag b)
{
return a.sx<b.sx;
}
bool cmpq(QUERY a,QUERY b)
{
return a.qx<b.qx;
}
int main()
{
n=rd(),m=rd(),p1=rd(),p2=rd();
int i,j;
for(i=1;i<=n;i++) v[i]=rd();
for(top=0,i=1;i<=n;i++)
{
while(top&&v[st[top]]<v[i]) rm[st[top--]]=i;
lm[i]=st[top],st[++top]=i;
}
for(i=1;i<=n;i++)
{
if(lm[i]&&rm[i]) s1[++n1].sx=lm[i],s1[n1].sl=s1[n1].sr=rm[i],s1[n1].sv=p1;
if(i<n) s2[++n2].sx=i+1,s2[n2].sl=s2[n2].sr=i,s2[n2].sv=p1;
if(!rm[i]) rm[i]=n+1;
if(lm[i]&&rm[i]>i+1) s1[++n1].sx=lm[i],s1[n1].sl=i+1,s1[n1].sr=rm[i]-1,s1[n1].sv=p2;
if(rm[i]<=n&&lm[i]<i-1) s2[++n2].sx=rm[i],s2[n2].sl=lm[i]+1,s2[n2].sr=i-1,s2[n2].sv=p2;
}
sort(s1+1,s1+n1+1,cmps),sort(s2+1,s2+n2+1,cmps);
for(i=1;i<=m;i++)
{
q[i].qx=q[i].ql=q[i+m].ql=rd(),q[i+m].qx=q[i].qr=q[i+m].qr=rd();
q[i].qx--,q[i].org=i=q[i+m].org=i,q[i].qv=-1,q[i+m].qv=1;
}
sort(q+1,q+2*m+1,cmpq);
for(i=j=1;i<=2*m;i++)
{
if(!q[i].qx) continue;
for(;j<=n1&&s1[j].sx<=q[i].qx;j++) modify(s1[j].sl-1,-s1[j].sv),modify(s1[j].sr,s1[j].sv);
ans[q[i].org]+=q[i].qv*(ask(q[i].qr)-ask(q[i].ql-1));
}
sa.init(),sb.init();
for(i=j=1;i<=2*m;i++)
{
if(!q[i].qx) continue;
for(;j<=n2&&s2[j].sx<=q[i].qx;j++) modify(s2[j].sl-1,-s2[j].sv),modify(s2[j].sr,s2[j].sv);
ans[q[i].org]+=q[i].qv*(ask(q[i].qr)-ask(q[i].ql-1));
}
for(i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}

【BZOJ4826】[Hnoi2017]影魔 单调栈+扫描线的更多相关文章

  1. [BZOJ4826] [HNOI2017] 影魔 单调栈 主席树

    题面 因为是一个排列,所以不会有重复的.如果有重复就没法做了.一开始没有仔细看题目想了半天. 发现,如果是第一种情况,那么边界\(l\)和\(r\)就应该分别是整个区间的最大值和次大值. 然后,对于那 ...

  2. 【bzoj4826】[Hnoi2017]影魔 单调栈+可持久化线段树

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

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

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

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

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

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

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

  6. P3722 [AH2017/HNOI2017]影魔(单调栈+扫描线+线段树)

    题面传送门 首先我们把这两个贡献翻译成人话: 区间 \([l,r]\) 产生 \(p_1\) 的贡献当且仅当 \(a_l,a_r\) 分别为区间 \([l,r]\) 的最大值和次大值. 区间 \([l ...

  7. bzoj4826 [Hnoi2017]影魔

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

  8. 【CF815D】Karen and Cards 单调栈+扫描线

    [CF815D]Karen and Cards 题意:一张卡片有三个属性a,b,c,其上限分别为A,B,C,现在有n张卡片,定义一张卡片能打败另一张卡片当且仅当它的至少两项属性要严格大于另一张的对应属 ...

  9. [BZOJ4826][HNOI2017]影魔 可持久化线段树

    链接 题意:给你 \(1\) 到 \(n\) 的排列 \(k_1,k_2,\dots,k_n\) ,对 \(i,j (i<j)\)来说,若不存在 \(k_s (i<s<j)\) 大于 ...

随机推荐

  1. 【转载】51CTO-Android设置模拟器屏幕大小

    在Eclipse Android中设置模拟器屏幕大小是本文要介绍的内容,主要是来了解并学习Eclipse Android中模拟器的设置,具体关于Eclipse Android内容的详解来看本文.   ...

  2. Codeforces 897 C.Nephren gives a riddle-递归

    C. Nephren gives a riddle   time limit per test 2 seconds memory limit per test 256 megabytes input ...

  3. 几个相似的DP题

    HDU1398 题意:把一个整数分拆成1.4.9.16.…….256.289(注意:只到289)这17个完全平方数的和,有几种方法. 解法不用说自然是DP,因为搜索显然超时. (这样的题我一般不敢开i ...

  4. BitMap与RoaringBitmap、JavaEWAH

    本文主要介绍BitMap的算法思想,以及开源工具类JavaEWAH.RoaringBitmap的简单用法. 一.BitMap 介绍 BitMap使用bit位,来标记元素对应的Value.该算法能够节省 ...

  5. 注意这几点,轻轻松松配置 Nginx + Tomcat 的集群和负载均衡

    Tomcat 集群是当单台服务器达到性能瓶颈,通过横向扩展的方式提高整体系统性能的有效手段.Nginx 是一个高性能的 HTTP 和反向代理 web 服务器,可以通过简单的配置实现 Tomcat 集群 ...

  6. 洛谷——P1306 斐波那契公约数

    P1306 斐波那契公约数 题目描述 对于Fibonacci数列:1,1,2,3,5,8,13......大家应该很熟悉吧~~~但是现在有一个很“简单”问题:第n项和第m项的最大公约数是多少? 输入输 ...

  7. window环境下使用PHP OpenSSL扩展函数返回false的原因

    window环境下使用PHP OpenSSL扩展函数返回false的原因(openssl_pkey_new) 使用的开发环境是PHPstudy ,在使用OpenSSL的函数openssl_pkey_n ...

  8. Scut游戏服务器引擎6.5.8.6发布

    1.增加从Redis中加载数据到Cache可设置筛选条件2.修改在Web项目中的不能支持自定协议问题3.修改Share类型的Model在Redis中为空时会尝试从DB中加载数据4.修改Model命名空 ...

  9. SVN merge 三种方式

    1.Merge a range of revisions 2.Reintegrate a branch 3.Merge two different trees ———————————————————— ...

  10. 转: 学习Javascript闭包(Closure) (阮一峰)

    from: http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html