BZOJ4540 [Hnoi2016] Sequence [Mo team + ST table + monotonic stack]

topic

  Given a sequence of length n: a1,a2,...,an, denoted as a[1:n]. Similarly, a[l:r] (1≤l≤r≤N) refers to the sequence: al,al+1,...,ar-
1,ar. If 1≤l≤s≤t≤r≤n, then a[s:t] is said to be a subsequence of a[l:r]. Now there are q queries, each query is given two numbers l and r, 1≤l≤r≤n
, find the sum of the minimum values ​​of different subsequences of a[l:r]. For example, given the sequence 5, 2, 4, 1, 3, and asking the given two numbers to be 1 and 3, then a[1:3] has
6 subsequences a[1:1], a[2:2 ],a[3:3],a[1:2],a[2:3],a[1:3], the sum of the minimum values ​​of these 6 subsequences is 5+2+4+2+2+ 2=17.

input format

  The first line of the input file contains two integers n and q, representing the sequence length and the number of queries, respectively. The next line contains n integers, separated by spaces
, and the ith integer is ai, which is the value of the ith element of the sequence. The next q lines, each containing two integers l and r, represent a query.

output format

  For each query, output a line representing the answer to the query.

input sample

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^9

answer

Considering Mo team,
we only need to consider how to extend the interval \(O(1)\)
Extending the left and right endpoints is similar,
taking the right endpoint as an example

The newly generated subintervals must be those subintervals with the new right endpoint \(r\) as the right endpoint,
then consider the influence of all left endpoints
from the position of the minimum value of the interval to the left endpoint of the interval, and the left endpoint is within this interval. The contribution must be the minimum value of the interval
. As for the contribution of the left endpoint in the right half of the interval, let's consider:
from \(r\) to a position smaller than \(A[r]\) \(pos\) , the answer Always \(A[r]\)
then start from \(pos\) , go to the left to a position smaller than \(A[pos]\) , the answer is always \(A[pos]\)
and so on

If you connect each position to the first position smaller than it, this is a tree structure, we only use \(O(1)\) to find the distance between the two points of the tree chain to solve the answer of the right half interval
Building a tree can be implemented with a monotonic stack

We can then use the \(ST\) table to maintain the minimum value to achieve \(O(1)\) extended range

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 100005,maxm = 100005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
int h[maxn],ne = 1;
struct EDGE{int to,nxt;}ed[maxn];
inline void build(int u,int v){
    ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;
}
LL Ls[maxn],Rs[maxn];
LL mn[maxn][18],n,Q,A[maxn],fa[maxn],fa1[maxn],bin[30],Log[maxn],B;
LL st[maxn],top,vis[maxn];
void dfs1(int u){
    vis[u] = true;
    if (fa[u]) Ls[u] = Ls[fa[u]] + (u - fa[u]) * A[u];
    Redge(u) {
        fa[to = ed[k].to] = u;
        dfs1(to);
    }
}
void dfs2(int u){
    vis[u] = true;
    if (fa1[u]) Rs[u] = Rs[fa1[u]] + (fa1[u] - u) * A[u];
    Redge(u) {
        fa1[to = ed[k].to] = u;
        dfs2(to);
    }
}
void init(){
    REP(j,17) REP(i,n){
        if (i + bin[j] - 1 > n) break;
        mn[i][j] = A[mn[i][j - 1]] <= A[mn[i + bin[j - 1]][j - 1]] ? mn[i][j - 1] : mn[i + bin[j - 1]][j - 1];
    }
    REP(i,n){
        while (top && A[st[top]] > A[i]) top--;
        if (top) build(st[top],i);
        st[++top] = i;
    }
    REP(i,n) if (!vis[i]) fa[i] = 0,dfs1(i);
    top = 0; memset(vis,0,sizeof(vis)); memset(h,0,sizeof(h)); ne = 1;
    for (int i = n; i; i--){
        while (top && A[st[top]] > A[i]) top--;
        if (top) build(st[top],i);
        st[++top] = i;
    }
    for (int i = n; i; i--) if (!vis[i]) fa1[i] = 0,dfs2(i);
}
int getmn(int l,int r){
    int t = Log[r - l + 1];
    return A[mn[l][t]] <= A[mn[r - bin[t] + 1][t]] ? mn[l][t] : mn[r - bin[t] + 1][t];
}
struct Que{int l,r,id,b;}q[maxn];
LL ans[maxn];
inline bool operator <(const Que& a,const Que& b){
    return a.b == b.b ? a.r < b.r : a.l < b.l;
}
void solve(){
    sort(q + 1,q + 1 + Q);
    LL tot = 0,L = q[1].l,R = q[1].r,pos;
    for (int i = L; i <= R; i++){
        pos = getmn(L,i);
        if (A[pos] == A[i]) tot += (i - L + 1) * A[i];
        else tot += (pos - L + 1) * A[pos] + Ls[i] - Ls[pos];
    }
    ans[q[1].id] = tot;
    for (int i = 2; i <= Q; i++){
        while (L != q[i].l || R != q[i].r){
            if (L > q[i].l){
                L--;
                pos = getmn(L,R);
                if (A[pos] == A[L]) tot += (R - L + 1) * A[L];
                else tot += (R - pos + 1) * A[pos] + Rs[L] - Rs[pos];
            }
            if (L < q[i].l){
                pos = getmn(L,R);
                if (A[pos] == A[L]) tot -= (R - L + 1) * A[L];
                else tot -= (R - pos + 1) * A[pos] + Rs[L] - Rs[pos];
                L++;
            }
            if (R < q[i].r){
                R++;
                pos = getmn(L,R);
                if (A[pos] == A[R]) tot += (R - L + 1) * A[R];
                else tot += (pos - L + 1) * A[pos] + Ls[R] - Ls[pos];
            }
            if (R > q[i].r){
                pos = getmn(L,R);
                if (A[pos] == A[R]) tot -= (R - L + 1) * A[R];
                else tot -= (pos - L + 1) * A[pos] + Ls[R] - Ls[pos];
                R--;
            }
        }
        ans[q[i].id] = tot;
    }
    REP(i,Q) printf("%lld\n",ans[i]);
}
int main(){
    bin[0] = 1; for (int i = 1; i <= 25; i++) bin[i] = bin[i - 1] << 1;
    Log[0] = -1; for (int i = 1; i < maxn; i++) Log[i] = Log[i >> 1] + 1;
    n = read(); Q = read();
    REP(i,n) A[i] = read(),mn[i][0] = i;
    init();
    B = (int)sqrt(n) + 1;
    REP(i,Q){
        q[i].l = read(); q[i].r = read(); q[i].id = i; q[i].b = q[i].l / B;
    }
    solve();
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325321211&siteId=291194637