BZOJ 3545: [ONTAK2010]Peaks

题目

离线做法:将所有的边和询问按照边权从小到大排序,遇到边就合并两个端点所在的线段树,遇到询问就查询该点所在的权值线段树中第 k 大的值。

一开始写线段树合并没有开并查集(雾
而且空间还开小了,胡乱调了半天,线段树合并的空间复杂度应该是 n l o g n

#include <cstdio>
#include <algorithm>

const int N = 2000005, M = 100005;

struct Node {
    int a, b, c, d; bool f;
    bool operator < (const Node &cmp) const {
        if (c == cmp.c) return f == 0;
        return c < cmp.c;
    }
} a[1000005];

struct Hill {
    int h, id;
    bool operator < (const Hill &cmp) const {
        return h < cmp.h;
    }
} h[M];

int n, m, q, sum[N], lson[N], rson[N], root[M], fa[M], cnt, ans[500005];

int read() {
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
int find(int x) {
    if (x != fa[x]) fa[x] = find(fa[x]);
    return fa[x];
}
void insert(int &cur, int l, int r, int p) {
    if (!cur) cur = ++cnt;
    ++sum[cur];
    if (l == r) return;
    int mid = l + (r - l >> 1);
    if (p <= mid) insert(lson[cur], l, mid, p);
    else insert(rson[cur], mid + 1, r, p);
}
int merge(int x, int y) {
    if (!x) return y;
    if (!y) return x;
    sum[x] += sum[y];
    lson[x] = merge(lson[x], lson[y]);
    rson[x] = merge(rson[x], rson[y]);
    return x;
}
int query(int cur, int l, int r, int k) {
    if (l == r) return l;
    int mid = l + (r - l >> 1);
    if (sum[lson[cur]] >= k) return query(lson[cur], l, mid, k);
    return query(rson[cur], mid + 1, r, k - sum[lson[cur]]);
}

int main() {
    n = read(), m = read(), q = read();
    for (int i = 1; i <= n; ++i) h[i].h = read(), h[i].id = i;
    std::sort(h + 1, h + n + 1);
    for (int i = 1; i <= n; ++i) insert(root[h[i].id], 1, n, i), fa[i] = i;
    for (int i = 1; i <= m; ++i)
        a[i].a = read(), a[i].b = read(), a[i].c = read(), a[i].f = 0;
    for (int i = m + 1; i <= m + q; ++i)
        a[i].a = read(), a[i].c = read(), a[i].b = read(), a[i].f = 1, a[i].d = i - m;
    std::sort(a + 1, a + m + q + 1);
    for (int i = 1; i <= m + q; ++i) {
        if (a[i].f == 0) {
            int fx = find(a[i].a), fy = find(a[i].b);
            if (fx == fy) continue;
            root[fy] = merge(root[fx], root[fy]), fa[fy] = fx;
        } else {
            int fx = find(a[i].a);
            if (a[i].b > sum[root[fx]]) ans[a[i].d] = -1;
            else ans[a[i].d] = query(root[fx], 1, n, sum[root[fx]] - a[i].b + 1);
        }
    }
    for (int i = 1; i <= q; ++i) {
        if (ans[i] == -1) puts("-1");
        else printf("%d\n", h[ans[i]].h);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/milkyyyyy/article/details/81137801
今日推荐