BZOJ 3551: [ONTAK2010]Peaks加强版

Kruskal重构树。

引用PoPoQQQ的一张图:

只要建出树,每次从点 v 向上倍增到最高的权值小于等于 x 的点 u ,然后查询主席树 r o o t [ u ] 中第 k 大的值即可。

(交上去一直显示 T L E ,然后就使劲卡常啊卡常啊,但发现其实是 M L E 了 QAQ 辣鸡bzoj
(显然是我内存算大了,而且还大了不少,虽然是 5 10 5 次合并,但最多只会新添 10 5 1 个节点!!!
(而且主席树的节点个数最多是 10 5 l o g 10 5 + 10 5 l o g 10 5 = 17 10 5 + 17 10 5 个:第一个 17 10 5 是一开始的最底层的 10 5 个节点,每个节点都会生成一条链;第二个 10 5 是二叉树上前 16 层的 10 5 1 个节点,每个节点也会带着一条链

#include <cstdio>
#include <cstring>
#include <algorithm>

const int N = 100005, M = 500005, X = 3400005;

int fa[N<<1], faa[N<<1], val[N], f[N<<1][18], root[N<<1], sum[X], lson[X], rson[X], cnt, node, n;

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

struct Edge {
    int u, v, c;
    bool operator < (const Edge &cmp) const {
        return c < cmp.c;
    }
} e[M];

int read() {
    int x = 0; char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x;
}
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);
}
void merge(int &cur, int x, int y, int l, int r) {
    if (!cur) cur = ++cnt;
    sum[cur] = sum[x] + sum[y];
    if (l == r) return;
    int mid = l + (r - l >> 1);
    if (lson[x] && lson[y]) merge(lson[cur], lson[x], lson[y], l, mid);
    else if (lson[x]) lson[cur] = lson[x];
    else if (lson[y]) lson[cur] = lson[y];
    if (rson[x] && rson[y]) merge(rson[cur], rson[x], rson[y], mid + 1, r);
    else if (rson[x]) rson[cur] = rson[x];
    else if (rson[y]) rson[cur] = rson[y];
}
int jump(int v, int x) {
    for (int i = 17; i >= 0; --i)
        if (f[v][i] && val[f[v][i]-n] <= x) v = f[v][i];
    return v;
}
int query(int cur, int l, int r, int k) {
    if (l == r) return a[l].h;
    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(); int m = read(), q = read();
    for (int i = 1; i <= n; ++i) a[i].h = read(), a[i].id = i;
    std::sort(a + 1, a + n + 1);
    for (int i = 1; i <= n; ++i) insert(root[a[i].id], 1, n, i), fa[i] = i;
    for (int i = 1; i <= m; ++i)
        e[i].u = read(), e[i].v = read(), e[i].c = read();
    std::sort(e + 1, e + m + 1);
    node = n;
    for (int i = 1; i <= m; ++i) {
        int fx = find(e[i].u), fy = find(e[i].v);
        if (fx == fy) continue;
        fa[++node] = fa[fx] = fa[fy] = faa[fx] = faa[fy] = node;
        val[node-n] = e[i].c;
        merge(root[node], root[fx], root[fy], 1, n);
    }
    for (int i = 1; i <= node; ++i) f[i][0] = faa[i];
    for (int j = 1; j <= 17; ++j)
        for (int i = 1; i <= node; ++i)
            f[i][j] = f[f[i][j-1]][j-1];
    int lastans = 0;
    while (q--) {
        int v = read(), x = read(), k = read();
        if (lastans != -1) v ^= lastans, x ^= lastans, k ^= lastans;
        int u = jump(v, x);
        if (sum[root[u]] < k) lastans = -1;
        else lastans = query(root[u], 1, n, sum[root[u]] - k + 1);
        printf("%d\n", lastans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Milkyyyyy/article/details/81148412
今日推荐