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;
}