洛谷P3402 模板 可持久化並查集

2022-05-02 15:06:11 字數 1594 閱讀 7072

n個集合 m個操作

1 a b 合併a,b所在集合

2 k 回到第k次操作之後的狀態(查詢算作操作)

3 a b 詢問a,b是否屬於同一集合,是則輸出1否則輸出0

5 6

1 1 2

3 1 2

2 03 1 2

2 13 1 210

1\(1 \le n \le 10^5, 1 \le m \le 2 \times 10^5\)

by zky 出題人大神犇

可持久化線段樹維護fa和rank/size

按秩合併/啟發式合併

#include #include #include #include #include #include #include inline int max(int a, int b)

inline int min(int a, int b)

inline void swap(int &x, int &y)

inline void read(int &x)

const int inf = 0x3f3f3f3f;

const int maxn = 400000 + 10;

struct node

node[maxn * 40];

int tot, n, m, fa[maxn], now, pos[maxn], cnt;

void build(int &o, int l = 1, int r = n)

int mid = (l + r) >> 1;

build(node[o].ls, l, mid);

build(node[o].rs, mid + 1, r);

}void insert(int &o, int oo, int p, int k, int l = 1, int r = n)

int mid = (l + r) >> 1;

if(p <= mid) insert(node[o].ls, node[oo].ls, p, k, l, mid), node[o].rs = node[oo].rs;

else insert(node[o].rs, node[oo].rs, p, k, mid + 1, r), node[o].ls = node[oo].ls;

}void add(int o, int p, int l = 1, int r = n)

int mid = (l + r) >> 1;

if(p <= mid) add(node[o].ls, p, l, mid);

else add(node[o].rs, p, mid + 1, r);

}int ask_f(int o, int p, int l = 1, int r = n)

int ask_rank(int o, int p, int l = 1, int r = n)

int find(int k, int x)

}void merge(int k, int x, int y)

int main()

else if(tmp1 == 2)

else

}return 0;

}

洛谷 P3402 可持久化並查集

解題思路 可持久化並查集也就是可持續化線段樹 並查集 主席樹 並查集 像我們平常做的並查集都是路徑壓縮,但因為要保證可持續化,所以資訊不能改變,所以我們採用啟發式合併來合併集合。啟發式合併的樹最高深度不會超過log n 1。因為深度為2的樹需要兩個點,那麼深度為3的需要兩個深度為2的也就是2 2 4...

P3402 模板 可持久化並查集

其實看看 自己就可以懂。注意 1.並查集不壓縮路徑,壓縮了就回不到壓縮之前的狀態了。2.並查集合並時,小的往大的合併,啟發式合併。3.對於第i步 不管什麼操作 操作都要把root i roo i 1 我在合併時,如果兩個祖先一樣就直接continue了,沒把root i 賦值為root i 1 一直...

P3402 模板 可持久化並查集

今天看到這道題,忽然不知道為何要線段樹了 笑 出現了一些瞎搞的想法 然後就想到了操作樹。就是,我們可以離線,然後每個位置直接維護乙個棧,記錄歷史資訊。然鵝我也不知道為什麼常數很大 include define r register int using namespace std namespace ...