【BZOJ4540】【HNOI2016】序列 [莫隊][RMQ]

序列

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

Description

  給定長度爲n的序列:a1,a2,…,an,記爲a[1:n]。
  相似地,a[l:r](1≤l≤r≤N)是指序列:al,al+1,…,ar-1,ar。
  若1≤l≤s≤t≤r≤n,則稱a[s:t]是a[l:r]的子序列。
  如今有q個詢問,每一個詢問給定兩個數l和r,1≤l≤r≤n,求a[l:r]的不一樣子序列的最小值之和。php

  例如,給定序列5,2,4,1,3,詢問給定的兩個數爲1和3,
  那麼a[1:3]有6個子序列a[1:1],a[2:2],a[3:3],a[1:2],a[2:3],a[1:3],
  這6個子序列的最小值之和爲5+2+4+2+2+2=17。ios

Input

  輸入文件的第一行包含兩個整數n和q,分別表明序列長度和詢問數。
  接下來一行,包含n個整數,以空格隔開,第i個整數爲ai,即序列第i個元素的值。接下來q行,每行包含兩個整數l和r,表明一次詢問。

ide

Output

  對於每次詢問,輸出一行,表明詢問的答案。spa

Sample Input

  5 5
  5 2 4 1 3
  1 5
  1 3
  2 4
  3 5
  2 5

Sample Output

  28
  17
  11
  11
  17

HINT

  1 ≤N,Q ≤ 100000,|Ai| ≤ 10^93d

Solution

  

Code

 1 #include<iostream>  
 2 #include<string>  
 3 #include<algorithm>  
 4 #include<cstdio>  
 5 #include<cstring>  
 6 #include<cstdlib>  
 7 #include<cmath>
 8 using namespace std;  9 typedef long long s64;  10 
 11 const int ONE = 100005;  12 const int INF = 2147483640;  13 
 14 int n,m;  15 int block[ONE],Q;  16 int a[ONE],pL[ONE],pR[ONE];  17 int stk[ONE],top;  18 int Log[ONE],Bin[ONE],MinD[ONE][19],NumD[ONE][19];  19 s64 Fl[ONE],Fr[ONE];  20 s64 ans,Ans[ONE];  21 
 22 struct power  23 {  24         int id;  25         int l,r;  26 }oper[ONE];  27 
 28 inline bool cmp(const power &a,const power &b)  29 {  30         if(block[a.l] != block[b.l]) return block[a.l] < block[b.l];  31         return a.r < b.r;  32 }  33 
 34 inline int get()  35 {  36         int res=1,Q=1;  char c;  37         while( (c=getchar())<48 || c>57)  38         if(c=='-')Q=-1;  39         if(Q) res=c-48;  40         while((c=getchar())>=48 && c<=57)  41         res=res*10+c-48;  42         return res*Q;  43 }  44 
 45 inline void Pre_Rmq()  46 {  47         Log[0]=-1;  for(int i=1;i<=n;i++) Log[i] = Log[i>>1] + 1;  48         Bin[0]=1;   for(int i=1;i<=17; i++) Bin[i] = Bin[i-1] << 1;  49         
 50         for(int j=1;j<=17;j++)  51         for(int i=1;i<=n;i++)  52         if(i+Bin[j]-1 <= n)  53  {  54             int Next = i + Bin[j-1];  55             if(MinD[i][j-1] < MinD[Next][j-1])  56                 MinD[i][j] = MinD[i][j-1], NumD[i][j] = NumD[i][j-1];  57             else
 58                 MinD[i][j] = MinD[Next][j-1], NumD[i][j] = NumD[Next][j-1];  59  }  60         else break;  61 }  62 
 63 inline int Get(int x,int y)  64 {  65         int T = Log[y - x +1];  66         if(MinD[x][T] < MinD[y-Bin[T]+1][T]) return NumD[x][T];  67         return NumD[y-Bin[T]+1][T];  68 }  69 
 70 inline void MakepL()  71 {  72         top = 0;  73         for(int i=n;i>=1;i--)  74  {  75             while(top && a[stk[top]] > a[i])  76                 pL[stk[top--]] = i;  77             stk[++top] = i;  78  }  79         while(top) pL[stk[top--]] = 0;  80         for(int i=1;i<=n;i++) pL[i]++;  81 }  82 
 83 inline void MakepR()  84 {  85         top = 0;  86         for(int i=1;i<=n;i++)  87  {  88             while(top && a[stk[top]] > a[i])  89                 pR[stk[top--]] = i;  90             stk[++top] = i;  91  }  92         while(top) pR[stk[top--]] = n+1;  93         for(int i=1;i<=n;i++) pR[i]--;  94 }  95 
 96 inline s64 DealL(int l,int r)  97 {  98         int pos = Get(l,r);  99         return (s64)a[pos] * (r-pos+1) + Fr[l] - Fr[pos]; 100 } 101 
102 inline s64 DealR(int l,int r) 103 { 104         int pos = Get(l,r); 105         return (s64)a[pos] * (pos-l+1) + Fl[r] - Fl[pos]; 106 } 107 
108 int main() 109 { 110         n = get();    m = get();    Q = sqrt(n); 111         for(int i=1;i<=n;i++) 112  { 113             a[i] = get(); block[i] = (i-1)/Q+1; 114             MinD[i][0] = a[i]; NumD[i][0] = i; 115  } 116         
117  Pre_Rmq(); MakepL(); MakepR(); 118         for(int i=1;i<=n;i++) Fl[i] = Fl[pL[i]-1] + (s64)(i-pL[i]+1) * a[i]; 119         for(int i=n;i>=1;i--) Fr[i] = Fr[pR[i]+1] + (s64)(pR[i]-i+1) * a[i]; 120         
121         
122         for(int i=1;i<=m;i++) 123  { 124             oper[i].id = i; 125             oper[i].l = get();    oper[i].r = get(); 126  } 127         sort(oper+1, oper+m+1, cmp); 128         
129         int l = 1, r = 0; 130         for(int i=1;i<=m;i++) 131  { 132             while(r < oper[i].r) ans += DealR(l,++r); 133             while(oper[i].l < l) ans += DealL(--l,r); 134             while(r > oper[i].r) ans -= DealR(l,r--); 135             while(oper[i].l > l) ans -= DealL(l++,r); 136             
137             Ans[oper[i].id] = ans; 138  } 139         
140         for(int i=1;i<=m;i++) 141             printf("%lld\n",Ans[i]); 142 }
View Code
相關文章
相關標籤/搜索