1. 程式人生 > >BZOJ4826: [Hnoi2017]影魔

BZOJ4826: [Hnoi2017]影魔

mem 上下 cnblogs http 最大值 clu memory www 自己的

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
思路{   和去年的序列有點像啊...   對於一個點,單獨計算其作為區間最大值的貢獻,所以單調棧求出 $ L[i] $ 為左邊第一個大於它的數的位置, $ R[i] $ 為右邊第一個小於等於它的數的位置。   $ P1 $的貢獻只有點對 $ (L[i],R[i]) $ ,$P2$的貢獻又有 $ (L[i],j) $ , $ j $ 所屬的範圍是 $ (i,R[i]) $ ,和 $ (j,R[i]) $ , $ j $ 所屬的範圍是 $ (L[i],i) $.   那麽在平面內抽象成一條條線段,詢問抽象成兩條平行於 $x$ 軸的線段,   由於單獨考慮點,每條直線y值表示所代表的點.
  每條線段左右端點即為所產生的貢獻範圍.那線段的左右端點和上下端點都是$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;
}

  

BZOJ4826: [Hnoi2017]影魔