P8868 [NOIP2022] 比赛

求$$\sum_{p = l}^{r} \sum_{q =p}^{r} (\max_{p \le i \le q}a_i)(\max_{p \le j \le q}b_j)$$

有比较套路的扫描线做法。令 $f_i = \sum_{p =i}^{r}(\max_{p \le i \le r}a_i)(\max_{p \le j \le r}b_j)$。
线段树上维护 $S_{l} = \sum_{i=l}^{r}f_i$。我们将询问离线,从左向右扫描。

当扫描到 $i$ 时,记 $ap_i = \max_{1 \le k < i} k + 1,(a_k \ge a_i)$,同理也有 $bp_i$。
不妨设 $ap_i \le bp_i$。
我们发现,对于线段树上区间 $1 \sim ap_i$ 他们和之前一样增长。
对于 $ap_i + 1 \sim bp_i$ 增长变为 $a_i \times b_{bp_i}$。
超过 $bp_i$ 后变为 $a_i \times b_i$。总共有 $2 \times n$ 个断点,这可以用单调栈维护。

设计双半群模型:

我们设计 $D + D \to D$, $M \times D \to D$, $M \times M \to M$

对于如何维护标记,有比较方便的做法:直接维护一个多项式。最高次项是 $\sum a_i \times b_i$,所以我们维护半群 $D(X_i \times Y_i,X_i,Y_i,S,len)$。

然后是 $M(A_{x\times y},A_x,A_y,C_x,C_y,C)$。

咕咕咕.

#include<bits/stdc++.h>
using namespace std;

typedef unsigned long long ull;
const int N = 2.5e5 + 500;

int T, n, q;
int a[N], b[N];

struct info{
    ull sxy, sx, sy, s;
    //info(ull sxy, ull sx, ull sy, ull s) : sxy(sxy), sx(sx), sy(sy), s(s) {}
    bool empty() {return !(sxy || sx || sy || s);}
    void clear() {sxy = sx = sy = s = 0;}
    void de_b() {printf("%llu %llu %llu %llu\n", s, sx, sy, sxy);}
};

struct tag{
    ull axy, ax, ay, cx, cy, c;
    //tag(ull axy, ull ax, ull ay, ull cx, ull cy, ull c) : axy(axy), ax(ax), ay(ay), cx(cx), cy(cy), c(c) {}
    bool empty() {return !(axy || ax || ay || cx || cy || c);} 
    void clear() {axy = ax = ay = cx = cy = c = 0;}
    void de_b() {printf("%llu %llu %llu %llu %llu %llu\n",cx,cy,ax,ay,axy,c);} 
};

info merge(info x, info y) {
    x.sxy += y.sxy;
    x.sx += y.sx;
    x.sy += y.sy;
    x.s += y.s;
    return x;
}

tag merge(tag x, tag y) {
    if(y.cx && y.cy) y.c += x.c + x.axy * y.cx * y.cy + x.ax * y.cx + x.ay * y.cy;
    else if(y.cx) {
        y.ay += x.ay + y.cx * x.axy;
        y.c += x.c + x.ax * y.cx; 
    } else if(y.cy) {
        y.ax += x.ax + y.cy * x.axy;
        y.c += x.c + x.ay * y.cy;
    } else {
         y.axy += x.axy;
         y.ax += x.ax;
         y.ay += x.ay;
         y.c += x.c;
    }
    if(x.cx) y.cx = x.cx;
    if(x.cy) y.cy = x.cy;
    return y;
}

info merge(info x, tag y, int len) {
    x.s += x.sxy * y.axy + x.sx * y.ax + x.sy * y.ay + y.c * len;
    if(y.cx && y.cy) {
        x.sx = y.cx * len;
        x.sy = y.cy * len;
        x.sxy = y.cx * y.cy * len;
    } else if(y.cx) {
        x.sxy = y.cx * x.sy;
        x.sx = y.cx * len;
    } else if(y.cy) {
        x.sxy = y.cy * x.sx;
        x.sy = y.cy * len;
    }
    return x;
}

#define lc k << 1
#define rc lc | 1
#define lcon lc, l, mid
#define rcon rc, mid + 1, r
#define Mid int mid = l + r >> 1

info tem[N << 2];
tag  ad [N << 2];

void p_up(int k) {
    tem[k] = merge(tem[lc], tem[rc]);
    //tem[k].de_b();
}

void Ad(int k, int l, int r, tag a) {
    //tem[k].de_b();
    ad[k] = merge(a, ad[k]);
    tem[k] = merge(tem[k], a, r - l + 1);
    //tem[k].de_b();
}

void p_do(int k, int l, int r) {
    if(!ad[k].empty()) {
        Mid;  
        //ad[k].de_b();
        Ad(lcon, ad[k]), Ad(rcon, ad[k]);

        ad[k].clear();
    }
}

void modify(int k, int l, int r, int x, int y, tag a) {
    if(x <= l && r <= y)  {
        //cout << "Pre\n"; ad[k].de_b(), tem[k].de_b();
        Ad(k, l, r, a);
        //ad[k].de_b();
        //tem[k].de_b();
        return;
    }
    Mid; p_do(k, l, r); if(x <= mid) modify(lcon, x, y, a);
    if(y > mid) modify(rcon, x, y, a); p_up(k);
}

ull query(int k, int l, int r, int x, int y) {
    if(x <= l && r <= y) return tem[k].s; ull res = 0;
    Mid; p_do(k, l, r); if(x <= mid) res += query(lcon, x, y);
    if(y > mid) res += query(rcon, x, y); return res;
}

struct node{
    int l, r, id;
    node(int l, int r, int id) : l(l), r(r), id(id) {}
};

int sta[N], ta;
int stb[N], tb;
ull ans[N];
vector< node > qr[N];

int main() {

    scanf("%d %d", &T, &n);    

    for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for(int i = 1; i <= n; ++i) scanf("%d", &b[i]);

    scanf("%d", &q);

    for(int i = 1; i <= q; ++i) {
        int l, r;
        scanf("%d %d", &l, &r);
        qr[r].push_back(node(l, r, i)); 
    }

    for(int i = 1; i <= n; ++i) {
        while(ta && a[sta[ta]] < a[i]) ta--;
        //cout << "Add: "; tem[1].de_b();
        modify(1, 1, n, sta[ta] + 1, i, tag{0, 0, 0, (ull)a[i], 0, 0});
        //cout << "End: "; tem[1].de_b();
        sta[++ta] = i;
        while(tb && b[stb[tb]] < b[i]) tb--;
        //cout << "Add: "; tem[1].de_b();
        modify(1, 1, n, stb[tb] + 1, i, tag{0, 0, 0, 0, (ull)b[i], 0});
        //cout << "End: "; tem[1].de_b();
        stb[++tb] = i;
        modify(1, 1, n, 1, i, tag{1, 0, 0, 0, 0, 0});
        //tem[1].de_b();
        for(auto E : qr[i]) ans[E.id] = query(1, 1, n, E.l, i);
    }

    for(int i = 1; i <= q; ++i) printf("%llu\n", ans[i]);
    return 0;
}

习题: rsraogps

posted @ 2023-10-31 14:37  Saka_Noa  阅读(16)  评论(0)    收藏  举报  来源