luogu P6109 [Ynoi2009] rprmq

https://www.luogu.com.cn/problem/P6109

矩阵加,矩阵求最大值
一看就不太阳间
考虑对于一个询问矩阵,按照x从中间分开,另外一维差分,往左右两边分别跑一次历史最值线段树就是答案
然后就秒了
发现可以离线
然后就可以先对于x轴做一个猫树分治,然后把询问和修改挂在分治点(中间点)上,大力对于每个中间点往左往右跑历史最值线段树即可
有一些细节要注意,对于一个位置,必须先减后加,不然会得到非法的值
O ( n l o g 2 n + q l o g n ) O(nlog^2n+qlogn) O(nlog2n+qlogn)
代码脑子清醒点还是打得比较爽的
code:

#include<bits/stdc++.h>
#define ll long long
#define N 2000050
using namespace std;
struct TT {
    ll m, lm, tg, ltg, tg0;
};
struct SGT {
    TT t[N << 1];
    void ladd(int rt, ll v1, ll v2) {
        t[rt].lm = max(t[rt].lm, t[rt].m + v2);
        t[rt].ltg = max(t[rt].ltg, t[rt].tg + v2);
        t[rt].m += v1, t[rt].tg += v1;
    }
    void clear(int rt) {
        ladd(rt << 1, t[rt].tg, t[rt].ltg), ladd(rt << 1 | 1, t[rt].tg, t[rt].ltg);
        t[rt].tg = t[rt].ltg = 0;
        t[rt].lm = t[rt].m; t[rt].tg0 = 1;
    }
    void pushdown(int rt) {
        if(t[rt].tg0) {
            clear(rt << 1), clear(rt << 1 | 1);
            t[rt].tg0 = 0;
        }
        ladd(rt << 1, t[rt].tg, t[rt].ltg), ladd(rt << 1 | 1, t[rt].tg, t[rt].ltg);
        t[rt].tg = t[rt].ltg = 0;
    }
    void update(int rt) {
        t[rt].m = max(t[rt << 1].m, t[rt << 1 | 1].m);
        t[rt].lm = max(t[rt << 1].lm, t[rt << 1 | 1].lm);
    }
    void add(int rt, int l, int r, int L, int R, ll o) {
        if(L <= l && r <= R) {
            ladd(rt, o, o);
            return ;
        }
        int mid = (l + r) >> 1; pushdown(rt);
        if(L <= mid) add(rt << 1, l, mid, L, R, o);
        if(R > mid) add(rt << 1 | 1, mid + 1, r, L, R, o);
        update(rt);
    }
    ll query(int rt, int l, int r, int L, int R) { //printf("%d %d %d %d %d\n", rt, l, r, L, R);
        if(L <= l && r <= R) return t[rt].lm;
        int mid = (l + r) >> 1; ll ret = 0; pushdown(rt);
        if(L <= mid) ret = query(rt << 1, l, mid, L, R);
        if(R > mid) ret = max(ret, query(rt << 1 | 1, mid + 1, r, L, R));
        return ret;
    }
} T;

struct Q {
    int l, r, x, y, id;
};
vector<Q> q[N];
int cmpr(Q x, Q y) { return x.r < y.r; }
int cmpl(Q x, Q y) { return x.l > y.l; }

void qadd(int rt, int l, int r, Q o) {// printf("%d %d %d  %d %d   %d\n", rt, l, r, o.l, o.r, o.id);
    int mid = (l + r) >> 1;
    if(o.l <= mid && o.r >= mid) {q[rt].push_back(o); return;}
    if(o.r < mid) qadd(rt << 1, l, mid, o);
    else qadd(rt << 1 | 1, mid + 1, r, o);
}


int n, m, qu;

struct ha {
    int l, r, o;
};
vector<ha> a[N];
int cmp(ha x, ha y) { return x.o < y.o; }

void change(int rt, int o) {
    if(o == 1) {
        for(int i = 0; i < a[rt].size(); i ++) {
            T.add(1, 1, n, a[rt][i].l, a[rt][i].r, a[rt][i].o);
        }
    } else {
        for(int i = a[rt].size() - 1; i >= 0; i --) {
            T.add(1, 1, n, a[rt][i].l, a[rt][i].r, - a[rt][i].o);
        }
    }
}

Q qq[N];
ll ans[N];
void cdq(int rt, int l, int r) { int mid = (l + r) >> 1;
    for(int i = l; i <= mid; i ++) change(i, 1);
    int gs = 0;
    for(int i = 0; i < q[rt].size(); i ++) qq[++ gs] = q[rt][i];
    sort(qq + 1, qq + 1 + gs, cmpr);
    int now = 1;
    while(qq[now].r == mid && now <= gs) now ++;
    for(int i = mid + 1; i <= r; i ++) {
        change(i, 1);
        if(i == mid + 1) T.clear(1);
        while(qq[now].r == i && now <= gs) {
            ans[qq[now].id] = max(ans[qq[now].id], T.query(1, 1, n, qq[now].x, qq[now].y));
            now ++;
        }
    }
    for(int i = r; i > mid; i --) change(i, -1);
    if(l != r) cdq(rt << 1 | 1, mid + 1, r);
    
    
    gs = 0;
    for(int i = 0; i < q[rt].size(); i ++) qq[++ gs] = q[rt][i];
    sort(qq + 1, qq + 1 + gs, cmpl);
/*    if(mid == 3) {
        printf("**  %d   %d\n", gs, rt);
        for(int i = 1; i <= gs; i ++) printf("%d ", qq[i].id); printf("\n");
    }*/
    now = 1;
    for(int i = mid; i >= l; i --) {
        if(i == mid) T.clear(1);
        while(qq[now].l == i && now <= gs) {
            ans[qq[now].id] = max(ans[qq[now].id], T.query(1, 1, n, qq[now].x, qq[now].y));
            now ++;
        }
        change(i, -1);
    }
    if(l != r) cdq(rt << 1, l, mid);
}

int main() {
    scanf("%d%d%d", &n, &m, &qu);
    for(int i = 1; i <= m; i ++) {
        int l, r, x, y, o;
        scanf("%d%d%d%d%d", &l, &x, &r, &y, &o);
        a[l].push_back((ha){x, y, o}), a[r + 1].push_back((ha){x, y, - o});
    }
    for(int i = 1; i <= n; i ++) sort(a[i].begin(), a[i].end(), cmp);
    
    for(int i = 1; i <= qu; i ++) {
        int l, r, x, y;
        scanf("%d%d%d%d", &l, &x, &r, &y);
        qadd(1, 1, n,(Q){l, r, x, y, i});
    }
    cdq(1, 1, n);
    for(int i = 1; i <= qu; i ++) printf("%lld\n", ans[i]);
    return 0;
}
posted @ 2021-08-26 14:33  lahlah  阅读(61)  评论(0编辑  收藏  举报