[BZOJ]3674 可持久化并查集

来源:互联网 发布:php二维数组去掉重复值 编辑:程序博客网 时间:2024/04/28 20:46

3674: 可持久化并查集加强版

Time Limit: 15 Sec Memory Limit: 256 MB
Submit: 4051 Solved: 1503
[Submit][Status][Discuss]
Description

Description:
自从zkysb出了可持久化并查集后……
hzwer:乱写能AC,暴力踩标程
KuribohG:我不路径压缩就过了!
ndsf:暴力就可以轻松虐!
zky:……

n个集合 m个操作
操作:
1 a b 合并a,b所在集合
2 k 回到第k次操作之后的状态(查询算作操作)
3 a b 询问a,b是否属于同一集合,是则输出1否则输出0
请注意本题采用强制在线,所给的a,b,k均经过加密,加密方法为x = x xor lastans,lastans的初始值为0
0

题解

可持久化并查集… 其实我们发现每次合并如果按秩合并的话只会改变一个点的fa, 那么就好比主席树每次有一个点不同, 修改一条链. 那么我们就可以用主席树维护每个点的fa和每个点的rk(即按秩合并的rk). 按秩合并本身暴力爬树是log, 每次查fa也变成log, 那么就是log^2n的复杂度… 用主席树维护即可.
用路径压缩有两点不对:
1. 第i棵主席树的建立由于路径压缩会改变多个点的fa, 那么空间会增加很大一部分, 不像按秩合并只会改变一个点的fa.
2. 多次合并, 每次合并一个集合的root和一个单点, 触发find后等于无效. 这样多次操作就成了一条长链… 成一条长链后那么每次操作回到这个版本, 那么路径压缩就会很长.

#include<stdio.h>#include<algorithm>#define Boc register char#define Acce register intconst int maxn = 2e5 + 5;int n, m, ans;inline const int read(){    Acce x = 0;    Boc ch = getchar();    while (ch < '0' || ch > '9') ch = getchar();    while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();    return x;}struct node{    int fa, rk;    node *ls, *rs;}pool[maxn * 50], *root[maxn], *tail = pool;node* build(int lf, int rg){    node* bt = ++ tail;    if (lf == rg)    {        bt -> fa = lf, bt -> rk = 0;        return bt;    }    int mid = (lf + rg) >> 1;       bt -> ls = build(lf, mid);    bt -> rs = build(mid + 1, rg);    return bt;}void modify(node* &bt, node* pre, int lf, int rg, int pos, int val){    bt = ++ tail;    if(lf == rg) { bt -> fa  = val; return; }    int mid = (lf + rg) >> 1;    if(pos <= mid) bt -> rs = pre -> rs, modify(bt -> ls, pre -> ls, lf, mid, pos, val);    else bt -> ls = pre -> ls, modify(bt -> rs, pre -> rs, mid + 1, rg, pos, val);}node* query(node* bt, int lf, int rg, int pos){    if(lf == rg) return bt;    int mid = (lf + rg) >> 1;    if(pos <= mid) return query(bt -> ls, lf, mid, pos);    else return query(bt -> rs, mid + 1, rg, pos);}node* find(int u, int i){    node* p = query(root[i], 1, n, u);    if(u == p -> fa) return p;    return find(p -> fa, i);}int main(){    n = read(), m = read();    root[0] = build(1, n);    node *p, *q;    for (Acce i = 1; i <= m; ++ i)    {        int opt = read(), u, v;        if (opt == 1)        {            u = read(), v = read();            root[i] = root[i - 1];            u ^= ans, v ^= ans;            p = find(u, i - 1), q = find(v, i - 1);            if (p -> fa == q -> fa) continue;            if (p -> rk > q -> rk) std :: swap(p, q);            modify(root[i], root[i - 1], 1, n, p -> fa, q -> fa);             if(p -> rk == q -> rk) q -> rk ++;        }        if (opt == 2) u = read(), u ^= ans, root[i] = root[u];        if (opt == 3)        {            root[i] = root[i - 1];            u = read(), v = read();            u ^= ans, v ^= ans;            p = find(u, i), q = find(v, i);            ans = (p -> fa == q -> fa);            printf("%d\n", ans);        }    }}
阅读全文
0 0
原创粉丝点击