トピック
問題解決のアイデア
まず、重要な特性があります。特定のポイントから開始して最後まで下がってから、右下まで下がる必要があります。(1、i)から(1、I)
(1 、i)走到 ( x , y ) (x,y) (x 、y )的代价是和[y] −合計[i] +(x − y + i)∗ a [i]合計[y]-合計[i] +(x-y + i)* a [i]s u m [ y ]−s u m [ i ]+(x−そして+i )∗a [ i ]。
クエリが要点なので、LiChaoshuを直接使用して下凸包を維持できます。
コード
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#define lson rt * 2
#define rson rt * 2 + 1
typedef long long ll;
void read(int &x) {
x = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
}
void write(int x) {
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
const int N = 1e5 + 100;
struct node {
int l, r, id;
}qu[N];
bool operator < (node a, node b) {
return a.r < b.r;
}
int n, m;
int sa[N], sum[N], ans[N];
int get(int i, int d) {
if (i == 0) return 1e9;
return -sum[i] + (i - d) * sa[i];
}
int tree[N * 4];
void insert(int id, int l, int r, int rt) {
if (tree[rt] == 0) return void(tree[rt] = id);
int m = (l + r) / 2;
if (get(tree[rt], m) > get(id, m)) swap(tree[rt], id);
if (l == r) return;
if (get(tree[rt], r) > get(id, r)) insert(id, m + 1, r, rson);
else insert(id, l, m, lson);
}
void insert(int rl, int rr, int id, int l, int r, int rt) {
if (rl == l && rr == r) return void(insert(id, l, r, rt));
int m = (l + r) / 2;
if (rr <= m) insert(rl, rr, id, l, m, lson);
else if (m < rl) insert(rl, rr, id, m + 1, r, rson);
else {
insert(rl, m, id, l, m, lson);
insert(m + 1, rr, id, m + 1, r, rson);
}
}
int query(int id, int l, int r, int rt) {
if (l == r) return get(tree[rt], id);
int m = (l + r) / 2;
if (id <= m) return min(get(tree[rt], id), query(id, l, m, lson));
else return min(get(tree[rt], id), query(id, m + 1, r, rson));
}
int main() {
//freopen("0.txt", "r", stdin);
read(n);
for (int i = 1; i <= n; i++) read(sa[i]), sum[i] = sum[i - 1] + sa[i];
read(m);
for (int i = 1; i <= m; i++) read(qu[i].l), read(qu[i].r), qu[i].id = i;
sort(qu + 1, qu + m + 1);
for (int i = 1, j = 1; i <= n && j <= m; i++) {
insert(0, i, i, 0, n, 1);
while (j <= m && qu[j].r == i) {
ans[qu[j].id] = sum[i] + query(qu[j].r - qu[j].l, 0, n, 1);
j++;
}
}
for (int i = 1; i <= m; i++) write(ans[i]), puts("");
return 0;
}