Comet OJ - Contest #14 转转的数据结构题 珂朵莉树+树状数组
题意:有两个操作
操作1:给出n个操作,将区间为l到r的数字改为x
操作2:给出q个操作,输出进行了操作1中的第x到x+y-1操作后的结果
解法:
把询问离线,按照r从小到大排序
每次询问的时候,用珂朵莉树推平区间
求和,这个我们用树状数组维护即可
树状数组求出>=l的和
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> #define IT set<node>::iterator using namespace std; typedef long long ll; const int M = 5e5 + 10; int n, m, q; ll anss[M], bit[M]; struct node{ int l, r, w; mutable ll v; bool operator < (const node &rhs) const { return l < rhs.l; } }; struct note{ int l, r, id; ll v; }a[M], b[M]; set <node> s; void add(int i, ll x) { if(!i) return; while(i <= m) { bit[i] += x; i += i & (-i); } } ll query(int i) { ll ans = 0; while(i) { ans += bit[i]; i -= i & (-i); } return ans; } IT split(int pos) { IT it = s.lower_bound(node{pos}); if(it != s.end() && it->l == pos) return it; it--; int L = it->l, R = it->r, w = it->w; ll V = it->v; s.erase(it); s.insert(node{L, pos - 1, w, V}); return s.insert(node{pos, R, w, V}).first; } void modify(int l, int r, int w, ll v) { IT it2 = split(r + 1), it1 = split(l), it3 = it1; for(; it1 != it2; it1++) add(it1->w, -(it1->v) * (it1->r - it1->l + 1)); s.erase(it3, it2); s.insert(node{l, r, w, v}); add(w, v * (ll)(r - l + 1)); } bool cmp(note p, note q) { return p.r < q.r; } int main(){ scanf("%d%d%d", &m, &n, &q); s.insert(node{1, n, 0, 0}); 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, cmp); int j = 1; for(int i = 1; i <= q; i++) { while(j <= b[i].r && j <= m) modify(a[j].l, a[j].r, j, a[j].v), j++; //printf("anss %lld %lld\n", query(n), query(b[i].l - 1)); anss[b[i].id] = query(m) - query(b[i].l - 1); } for(int i = 1; i <= q; i++) printf("%lld\n", anss[i]); return 0; }