并查集

发布时间 2023-04-06 20:27:07作者: SunnyYuan

CF371D Vessels

点击查看题目

image

点击查看思路

定义一个权值并查集,权值保存这个集合还可以存下多少水。

如果这个集合可以存放的水已经小于要装入的水,就将这个集合与下一个集合合并。

否则,直接把这个集合可以存放的水减去要装入的水的体积。

点击查看代码
#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 200010;

int n, m;
int fa[N];
LL g[N], b[N];

int find(int x) {
    if (x == fa[x]) return x;
    return fa[x] = find(fa[x]);
}

int merge(int x, int y) {
    int fx = find(x), fy = find(y);
    if (fx == fy) return fx;
    fa[fx] = fy;
    g[fy] += g[fx];
    return fy;
}

void init() {
    for (int i = 1; i <= n; i++) fa[i] = i;
}

void modify(int x, LL v) {
    x = find(x);
    while (true) {
        if (g[x] >= v || x >= n) break;
        x = merge(x, x + 1);
    }
    g[x] = max(0ll, g[x] - v);
}

void query(int x) {
    int fx = find(x);
    if (fx == x) cout << b[x] - g[x] << '\n';
    else cout << b[x] << '\n';
}

int main() {
    #ifdef DEBUG
    freopen("D:/Exercise/Test.in", "r", stdin);
    clock_t st, ed;
    cout << "===================START===================" << endl;
    st = clock();
    #endif

    cin >> n;
    for (int i = 1; i <= n; i++) cin >> g[i], b[i] = g[i];
    init();
    cin >> m;
    int opt, a;
    LL b;
    for (int i = 1; i <= m; i++) {
        cin >> opt;
        if (opt == 1) { cin >> a >> b; modify(a, b); }
        else { cin >> a; query(a); }
    }

    #ifdef DEBUG
    ed = clock();
    cout << "====================END====================" << endl;
    cout << "Time:" << (ed - st) * 1.0 / CLOCKS_PER_SEC << " sec" << endl;
    #endif
    return 0;
}