BZOJ4826: [Hnoi2017]影魔

4826: [Hnoi2017]影魔

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 550  Solved: 300
[Submit][Status][Discuss]

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
思路{
  和去年的序列有点像啊...
  对于一个点,单独计算其作为区间最大值的贡献,这也是一般的序列问题的套路。
  对于单点$ i $,他所能作为一段区间内的最大值所能做出的贡献是什么,
  找出左边第一个大于$K_i$的位置$L_i$,
  右边第一个大于$K_i$的位置$R_i$
  一段区间做出的贡献,又十分自然想到了扫描线.
  由于设二维平面上的点$( x , y ) $  中$ y $值表示所代表的点.$x$值表示它所能够影响到的点。
  $P_1$对应了点$ ( i , L_i ) $到$ ( i , R_i ) $的线段,
  $P_2$对应了点$ ( L_i , i + 1 ) $到$ ( i , R_i - 1 ) $的线段,
  $P_2$对应了点$ ( R_i , L_i + 1 ) $到$ ( R_i , i - 1 ) $的线段,
  询问抽象成两条平行于 $ x $ 轴的线段,
  每条线段左右端点即为所产生的贡献范围.那线段的左右端点和上下端点都是$L,R$了.
  那么就是求询问所代表的区间内的权值和了!!
  用扫描线+区间修改树状数组维护这个东西即可.
  这么说来应该也可以用扫描线来解决去年的序列了.
}
#include<bits/stdc++.h>
#define il inline
#define RG register
#define ll long long
#define db double
#define N 200010
#define lowbit (i&-i)
using namespace std;
int l[N],r[N],st[N],a[N],n,m,p1,p2;
ll Ans[N];
namespace BIT{
  ll t1[N],t2[N];
  void clear(){memset(t1,0,sizeof(t1));memset(t2,0,sizeof(t2));}
  void add(int x,int y){
    for(int i=x;i<=n;i+=lowbit)t1[i]+=y,t2[i]+=1ll*x*y;
  }
  void Insert(int l,int r,int num){
    add(l,num),add(r+1,-num);
  }
  ll Query(int pos){
    ll Sum(0);
    for(int i=pos;i;i-=lowbit)Sum+=(pos+1)*t1[i]-t2[i];
    return Sum;
  }
  ll sum(int l,int r){
    return Query(r)-Query(l-1);
  }
}
struct event{
  int l,r,h,bel,val;
  event() {}
  event(int a,int b,int c,int d,int e):l(a),r(b),h(c),bel(d),val(e) {}
}eve1[N*2],eve2[N*3];int tot1,tot2;
bool comp(const event & a,const event & b){return a.h<b.h;}
int main(){
  scanf("%d%d%d%d",&n,&m,&p1,&p2);
  for(int i=1;i<=n;++i)scanf("%d",&a[i]);
  for(int i=1;i<=n;++i){
    while(st[0]&&a[st[st[0]]]<a[i])r[st[st[0]--]]=i;
    st[++st[0]]=i;
  }
  while(st[0])r[st[st[0]--]]=n+1;
  for(int i=n;i;i--){
    while(st[0]&&a[st[st[0]]]<a[i])l[st[st[0]--]]=i;
    st[++st[0]]=i;
  }
  while(st[0])l[st[st[0]--]]=0;
  for(int i=1;i<=m;++i){int l,r;
    scanf("%d%d",&l,&r);Ans[i]+=1ll*(r-l)*p1;
    eve1[++tot1]=event(l,r,r,i,1);
    eve1[++tot1]=event(l,r,l-1,i,-1);
  }
  sort(eve1+1,eve1+tot1+1,comp);
  for(int i=1;i<=n;++i){
    if(l[i]&&r[i]!=n+1)eve2[++tot2]=event(l[i],l[i],r[i],0,p1);
    if(l[i]&&r[i]>i+1)eve2[++tot2]=event(i+1,r[i]-1,l[i],0,p2);
    if(r[i]!=n+1&&l[i]+1<i)eve2[++tot2]=event(l[i]+1,i-1,r[i],0,p2);
  }
  sort(eve2+1,eve2+tot2+1,comp);
  int h1(1),h2(1);
  while(!eve1[h1].h)h1++;
  for(int i=1;i<=n&&h1<=tot1;++i){
    while(h2<=tot2&&eve2[h2].h==i){
      BIT::Insert(eve2[h2].l,eve2[h2].r,eve2[h2].val);
      h2++;
    }
    while(h1<=tot1&&eve1[h1].h==i){
      Ans[eve1[h1].bel]+=eve1[h1].val*(BIT::sum(eve1[h1].l,eve1[h1].r));
      h1++; 
    }
  }
  for(int i=1;i<=m;++i)cout<<Ans[i]<<"\n";
  return 0;
}

  

posted @ 2017-09-10 20:27  QYP_2002  阅读(583)  评论(3编辑  收藏  举报