Description
有
座山横着排成一行,从左到右编号为从
到
。山
的高度为
。每座山的顶上恰好住着一个人。
你打算举行 个会议,编号为从 到 。会议 的参加者为住在从山 到山 (包括 LjLj 和 RjRj )上的人 。对于该会议,你必须选择某个山 做为会议举办地 。举办该会议的成本与你的选择有关,其计算方式如下:
来自每座山
的参会者的成本,等于在山
和 yy 之间(包含
和
)的所有山的最大高度。特别地,来自山
的参会者的成本是
,也就是山
的高度。
会议的成本等于其所有参会者的成本之和。
你想要用最低的成本来举办每个会议。
注意,所有的参会者将在每次会议后回到他们自己的山;所以一个会议的成本不会受到先前会议的影响。
Sample Input
4 2
2 4 3 5
0 2
1 3
Sample Output
10
12
可以以传统方式提交。
我们考虑离线完成这个问题,我们把一个询问挂在这个区间的最大值上。
设区间
的答案为
,最大值的位置为
。
那么
那么这个结构就是一棵笛卡尔树。
对于每一个右端点,或左端点,我们考虑维护他到当前分治中心的答案。
左端点或右端点的问题你可以把这个串正反跑两遍,相当于你每次只用维护某个点作为右端点到分治中心的答案即可。
考虑更新某一段区间到分治中心的答案。
设我当前区间为
,分治中心为
那么我们对于线段树上的
中的每一个
都要让他们的值变成:
。
事实上这个区间中肯定会以一个点作为分界线,满足左边的值都取
,右边的值都取
。
那么可以通过在线段树上二分实现这个修改。
考虑证明上面的结论:
这个式子显然是满足的,即得证。
代码, 简单魔改就好了。
#include <ctime>
#include <cstdio>
#include <vector>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long LL;
LL _min(LL x, LL y) {return x < y ? x : y;}
const int N = 750001;
int read() {
int s = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * f;
}
void put(int x) {
if(x >= 10) put(x / 10);
putchar(x % 10 + '0');
}
LL ans[N];
int n, Q, h[N];
struct st_table {
int f[20][N], bin[21], Log[N];
int _max(int x, int y) {return h[x] >= h[y] ? x : y;}
void bt() {
bin[0] = 1; for(int i = 1; i <= 20; i++) bin[i] = bin[i - 1] * 2;
Log[1] = 0; for(int i = 2; i <= n; i++) Log[i] = Log[i >> 1] + 1;
for(int i = 1; i <= n; i++) f[0][i] = i;
for(int i = 1; bin[i] <= n; i++) {
for(int j = 1; j <= n - bin[i] + 1; j++) {
f[i][j] = _max(f[i - 1][j], f[i - 1][j + bin[i - 1]]);
}
}
}
int query(int l, int r) {
int hh = Log[r - l + 1];
return _max(f[hh][l], f[hh][r - bin[hh] + 1]);
}
} st;
struct query{int l, r;} g[N];
struct cc {LL a, b;};
vector<int> q[N];
struct tnode {
int lc, rc; LL c;
cc ad, cg;
};
struct segment {
tnode t[N << 1];
cc n1, n2;
int cnt;
void bt(int l, int r) {
int now = ++cnt;
t[now].lc = t[now].rc = -1;
t[now].c = 0, t[now].ad = t[now].cg = cc{0, 0};
if(l < r) {
int mid = (l + r) / 2;
t[now].lc = cnt + 1; bt(l, mid);
t[now].rc = cnt + 1; bt(mid + 1, r);
}
}
void build() {cnt = 0; bt(1, n);}
void change(int now, int r, cc x) {
t[now].cg = x; t[now].ad = cc{0, 0};
t[now].c = x.a + x.b * r;
}
void add(int now, int r, cc x) {
if(t[now].cg.a || t[now].cg.b) t[now].cg.a += x.a, t[now].cg.b += x.b;
else t[now].ad.a += x.a, t[now].ad.b += x.b;
t[now].c += x.a + x.b * r;
}
void pushdown(int now, int l, int r) {
int mid = (l + r) / 2;
if(t[now].cg.a || t[now].cg.b) {
change(t[now].lc, mid, t[now].cg);
change(t[now].rc, r, t[now].cg);
t[now].cg = cc{0, 0};
} if(t[now].ad.a || t[now].ad.b) {
add(t[now].lc, mid, t[now].ad);
add(t[now].rc, r, t[now].ad);
t[now].ad = cc{0, 0};
}
}
void Link(int now, int l, int r, int p, LL c) {
if(l == r) {t[now].c = c; return ;}
pushdown(now, l, r);
int mid = (l + r) / 2;
if(p <= mid) Link(t[now].lc, l, mid, p, c);
else Link(t[now].rc, mid + 1, r, p, c);
t[now].c = t[t[now].rc].c;
}
LL query(int now, int l, int r, int p) {
if(l == r) return t[now].c;
pushdown(now, l, r);
int mid = (l + r) / 2;
if(p <= mid) return query(t[now].lc, l, mid, p);
else return query(t[now].rc, mid + 1, r, p);
}
void G1(int now, int l, int r, int ll, int rr) {
if(ll == l && rr == r) {add(now, r, n1); return ;}
pushdown(now, l, r);
int mid = (l + r) / 2;
if(rr <= mid) G1(t[now].lc, l, mid, ll, rr);
else if(ll > mid) G1(t[now].rc, mid + 1, r, ll, rr);
else G1(t[now].lc, l, mid, ll, mid), G1(t[now].rc, mid + 1, r, mid + 1, rr);
t[now].c = t[t[now].rc].c;
}
void G2(int now, int l, int r, int ll, int rr) {
if(ll == l && rr == r) {change(now, r, n2); return ;}
pushdown(now, l, r);
int mid = (l + r) / 2;
if(rr <= mid) G2(t[now].lc, l, mid, ll, rr);
else if(ll > mid) G2(t[now].rc, mid + 1, r, ll, rr);
else G2(t[now].lc, l, mid, ll, mid), G2(t[now].rc, mid + 1, r, mid + 1, rr);
t[now].c = t[t[now].rc].c;
}
void gai(int now, int l, int r, int ll, int rr) {
if(l == r) {
t[now].c = _min(n2.a + n2.b * l, t[now].c + n1.a);
return ;
} pushdown(now, l, r);
int mid = (l + r) / 2;
if(rr <= mid) gai(t[now].lc, l, mid, ll, rr);
else if(ll > mid) gai(t[now].rc, mid + 1, r, ll, rr);
else {
if(t[t[now].lc].c + n1.a <= n2.a + n2.b * mid) {
gai(t[now].lc, l, mid, ll, mid);
G1(t[now].rc, mid + 1, r, mid + 1, rr);
} else {
gai(t[now].rc, mid + 1, r, mid + 1, rr);
G2(t[now].lc, l, mid, ll, mid);
}
} t[now].c = t[t[now].rc].c;
}
void modify(int l, int r, LL a, LL b, LL c) {
n1.a = b, n1.b = 0;
n2.a = a - c * l + c, n2.b = c;
gai(1, 1, n, l, r);
}
} t;
LL dfs(int l, int r) {
if(l > r) return 0;
if(l == r) {t.Link(1, 1, n, l, h[l]); return h[l];}
int mid = st.query(l, r);
LL lans = dfs(l, mid - 1);
LL rans = dfs(mid + 1, r);
t.Link(1, 1, n, mid, lans + h[mid]);
for(int i = 0; i < q[mid].size(); i++) {
int x = q[mid][i];
int ll = g[x].l, rr = g[x].r;
if(mid < rr) ans[x] = _min(ans[x], t.query(1, 1, n, rr) + (LL)(mid - ll + 1) * h[mid]);
} if(mid < r) t.modify(mid + 1, r, lans + h[mid], (LL)h[mid] * (mid - l + 1), h[mid]);
return t.query(1, 1, n, r);
}
void solve() {
st.bt();
for(int i = 1; i <= n; i++) q[i].clear();
for(int i = 1; i <= Q; i++) {
if(g[i].l == g[i].r) ans[i] = h[g[i].l];
else q[st.query(g[i].l, g[i].r)].push_back(i);
} t.build();
dfs(1, n);
}
int main() {
memset(ans, 63, sizeof(ans));
n = read(), Q = read();
for(int i = 1; i <= n; i++) h[i] = read();
for(int i = 1; i <= Q; i++) g[i].l = read() + 1, g[i].r = read() + 1;
solve();
reverse(h + 1, h + n + 1);
for(int i = 1; i <= Q; i++) g[i].l = n - g[i].l + 1, g[i].r = n - g[i].r + 1, swap(g[i].l, g[i].r);
solve();
for(int i = 1; i <= Q; i++) printf("%lld\n", ans[i]);
return 0;
}