Comet OJ #contest14 D.转转的数据结构题(珂朵莉树)

题目: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
 */
发布了156 篇原创文章 · 获赞 20 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/Cymbals/article/details/103051250