Luogu P3246 [HNOI2016] sequence (offline differential tree array)

meaning of the title

Title Link

Sol

It seems that a different method has been worked out from the solution of the question (however, it still exploded when I didn't write it out in the examination room)

An obvious idea is to consider the contribution of each minimum value.

Preprocess the first number on the left and the first number on the right.

Then \ ([L_i + 1, i] \) will contribute \ (a[i] \) to each number in \ ([i, R_i] \).

We can abstract it into a rectangular addition in a two-dimensional plane.

Query is to query the weights in the rectangle whose bottom corner is \ ((l, l) \) and upper right corner is \ ((r, r) \)

That is to say, we need to solve such a problem: two operations, rectangle plus rectangle sum, and the former is executed in front of the latter

We can add all the rectangle operations to the upper right and all the inquiry operations to the lower left. In this way, we only need to consider the influence of all the modifications \ ((x, y) \) in the lower left corner of each \ ((i, j) \), and the weight of this part is \ ((i - x + 1) * (j - y + 1) * w \)

It can be directly disassembled and found that it can be maintained by tree array (single point modification, check prefix and). And then it's done

Complexity \ (O(nlogn) \)

/*
*/
#include<bits/stdc++.h>
#define LL long long 
#define fi first
#define se second
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++)
char buf[(1 << 22)], *p1 = buf, *p2 = buf;
char obuf[1<<24], *O = obuf;
void print(int x) {if(x > 9) print(x / 10); *O++ = x % 10 + '0';}
#define OS  *O++ = '\n';
#define fout fwrite(obuf, O-obuf, 1 , stdout); 
using namespace std;
const int MAXN = 1e5 + 10, INF = 1e9 + 10;
template<typename A, typename B> inline bool chmax(A &x, B y) {return x < y ? x = y, 1 : 0;}
template<typename A, typename B> inline bool chmin(A &x, B y) {return x > y ? x = y, 1 : 0;}
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int N, M, Q, a[MAXN],  st[MAXN], L[MAXN], R[MAXN]; 
LL ans[MAXN];
struct Modify {
    int h;LL v;
};
vector<Modify> tag[MAXN];
struct Query {
    int h, id, opt;
};
vector<Query> q[MAXN];
void Add(int x1, int y1, int x2, int y2, int v) {
    tag[x1].push_back({y1, v});
    tag[x2 + 1].push_back({y1, -v});
    tag[x1].push_back({y2 + 1, -v});
    tag[x2 + 1].push_back({y2 + 1, v});
}
void Query(int x1, int y1, int x2, int y2, int id) {
    q[x2].push_back({y2, id, 1});
    q[x1 - 1].push_back({y2, id, -1});
    q[x2].push_back({y1 - 1, id, -1});
    q[x1 - 1].push_back({y1 - 1, id, 1});
}
#define lb(x) (x & (-x))
LL s1[MAXN], s2[MAXN], s3[MAXN], s4[MAXN];
void TreeAdd(int x, LL v1, LL v2, LL v3, LL v4) {
    while(x <= M) 
        s1[x] += v1, s2[x] += v2, s3[x] += v3, s4[x] += v4, x += lb(x);
}
pair<pair<LL, LL>, pair<LL, LL> > TreeQuery(int x) {
    pair<pair<LL, LL>, pair<LL, LL> > ans;
    while(x) 
        ans.fi.fi += s1[x], ans.fi.se += s2[x], ans.se.fi += s3[x], ans.se.se += s4[x], x -= lb(x);
    return ans;
}
#undef lb
void solve() {
    for(int i = 1; i <= M; i++) {   
        for(auto y: tag[i]) {
            int v = y.v;
            TreeAdd(y.h, 1ll * v, 1ll * (y.h - 1) * v, 1ll * (i - 1) * v, 1ll * (y.h - 1) * (i - 1) * v);
        }
        for(auto x : q[i]) {
            LL sumv = 0, sumyv = 0, sumxv = 0, sumxyv = 0;
            pair<pair<LL, LL>, pair<LL, LL> > tmp = TreeQuery(x.h);
            sumv = tmp.fi.fi;
            sumyv = tmp.fi.se;
            sumxv = tmp.se.fi;
            sumxyv = tmp.se.se;
            int j = x.h;
            ans[x.id] += 1ll * x.opt * (1ll * i * j * sumv - 1ll * i * sumyv - 1ll * j * sumxv + sumxyv);
        }
    }
}

void Pre() {
    a[0] = -INF; a[N + 1] = -INF; int top = 0;
    for(int i = 1; i <= N + 1; i++) {
        while(top && a[i] < a[st[top]]) R[st[top--]] = i;
        L[i] = st[top];
        st[++top] = i;
    }
    for(int i = 1; i <= N; i++)
        if((i <= R[i] - 1) && (L[i] + 1 <= i)) 
            Add(i, L[i] + 1, R[i] - 1, i, a[i]);
}
signed main() {
    //freopen("a.in", "r", stdin); freopen("b.out", "w", stdout);
    N = read(); M = N + 1; Q = read();
    for(int i = 1; i <= N; i++) a[i] = read();
    Pre();
    for(int i = 1; i <= Q; i++) {
        int l = read(), r = read(), ans = 0;
        Query(l, l, r, r, i);
    }
    solve();
    for(int i = 1; i <= Q; i++) cout << ans[i] << '\n';
    return 0;
}

Tags: C++

Posted on Mon, 02 Dec 2019 12:25:33 -0500 by billynastie2007