题目:https://cometoj.com/contest/73/problem/D?problem_id=4120
由于有“将一段区间全部变成v”这一操作,考虑使用珂朵莉树维护。
将所有查询离线按右端点排序,在每个查询询问前,将1到R的操作全部做完,然后使用线段树/树状数组查询大于当前询问的L的操作产生的贡献。
在珂朵莉树的节点中记录一下当前节点是由第几次操作产生,assigan时消除上次的贡献,加入现在的贡献,即可维护操作产生的区间和。
ac代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 5e5 + 5;
int n, m, q;
ll ans[maxn];
struct op {
int l, r;
ll v;
} a[maxn];
struct query {
int l, r, id;
friend bool operator<(const query &a, const query &b) {
return a.r < b.r;
}
} b[maxn];
struct node {
int l, r, id;
ll v;
friend bool operator<(const node &a, const node &b) {
return a.l < b.l;
}
};
ll t[maxn << 2];
void update(int rt, int l, int r, int pos, ll val) {
if (l == r) {
t[rt] += val;
return;
}
int mid = (l + r) >> 1;
if (pos <= mid) {
update(rt << 1, l, mid, pos, val);
} else {
update(rt << 1 | 1, mid + 1, r, pos, val);
}
t[rt] = t[rt << 1] + t[rt << 1 | 1];
}
ll query(int rt, int l, int r, int L, int R) {
if (l >= L && r <= R) {
return t[rt];
}
int mid = (l + r) >> 1;
ll ans = 0;
if (L <= mid) {
ans += query(rt << 1, l, mid, L, R);
}
if (R > mid) {
ans += query(rt << 1 | 1, mid + 1, r, L, R);
}
return ans;
}
set<node> cot;
void init(int l, int r, int v) {
cot.clear();
cot.insert({l, r, 0, v});
}
auto spilt(int x) {
if (x > n) {
return cot.end();
}
auto it = --cot.upper_bound({x, 0, 0, 0});
if (it->l == x) {
return it;
}
int l = it->l, r = it->r, v = it->v, id = it->id;
cot.erase(it);
cot.insert({l, x - 1, id, v});
return cot.insert({x, r, id, v}).first;
}
void assign(int l, int r, ll v, int id) {
//先split右端点,再split左端点
auto itr = spilt(r + 1), itl = spilt(l);
for (; itl != itr;) {
auto j = itl;
++itl;
update(1, 1, m, j->id, -1LL * (j->r - j->l + 1) * j->v);
cot.erase(j);
}
cot.insert({l, r, id, v});
update(1, 1, m, id, 1LL * (r - l + 1) * v);
}
int main() {
scanf("%d%d%d", &m, &n, &q);
for (int i = 1; i <= m; ++i) {
scanf("%d%d%lld", &a[i].l, &a[i].r, &a[i].v);
}
for (int i = 1; i <= q; ++i) {
scanf("%d%d", &b[i].l, &b[i].r);
b[i].id = i;
}
sort(b + 1, b + q + 1);
init(1, n, 0);
for (int i = 1; i <= q; ++i) {
for (int j = b[i - 1].r + 1; j <= b[i].r; ++j) {
assign(a[j].l, a[j].r, a[j].v, j);
}
ans[b[i].id] = query(1, 1, m, b[i].l, m);
}
for (int i = 1; i <= q; ++i) {
printf("%lld\n", ans[i]);
}
return 0;
}
/*
1 500000 1
1 500000 2000000000
1 1
*/