Comet OJ - Contest #14 转转的数据结构题 珂朵莉树+树状数组

题目链接:

题意:有两个操作

操作1:给出n个操作,将区间为l到r的数字改为x

操作2:给出q个操作,输出进行了操作1中的第x到x+y-1操作后的结果

解法:

把询问离线,按照r从小到大排序

每次询问的时候,用珂朵莉树推平区间

求和,这个我们用树状数组维护即可

树状数组求出>=l的和

#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;
}
View Code

猜你喜欢

转载自www.cnblogs.com/linglinga/p/12031153.html