【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]的不同子序列的最小值之和。
例如,给定序列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。
Input
输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数。
接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i个元素的值。接下来q行,每行包含两个整数l和r,代表一次询问。
Output
对于每次询问,输出一行,代表询问的答案。
Sample Input
5 5
5 2 4 1 3
1 5
1 3
2 4
3 5
2 5
5 2 4 1 3
1 5
1 3
2 4
3 5
2 5
Sample Output
28
17
11
11
17
17
11
11
17
HINT
1 ≤N,Q ≤ 100000,|Ai| ≤ 10^9
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 }