可持久化並查集(三)——從動態到可持久化
中已經可以算是一個偽可持久化了,但是對於歷史查詢等操作無能為力。。所以本篇重點介紹可持久化操作
BZOJ 3673
這題不知道出題人什麼做法,但是程式碼很短的樣子
UPD:出題人用的是rope,即stl中的可持久化平衡樹
KuribohG神犇告訴了我可以用可持久化線段樹實現可持久化陣列T T
既然都有可持久化陣列了,只要用個再並查集的啟發式合併就能妥妥的水過了(這樣每次只要修改一個fa)
並查集的啟發式合併就是按秩合併,初始所有集合秩為0
合併把秩小的樹根的父親設為秩大的樹根
如果秩相同,則隨便選取一個作為父節點並將它的秩+1
秩和fa一樣維護
但是其實這題資料隨機的話隨便合併就行了,根本不用按秩合併什麼的
UPD:秩其實有的時候很不好用,維護子樹大小比較贊。。。
另外,ndsf發現只要直接暴力就能虐了T T
引用自hzwer
所以可以發現暴力出奇跡大力發展可持久化並查集是解決當今膜蛤事件。。。的唯一方法!!
最終我們還是寫份正解(hfu說沒有正解,只有更好的暴力)
#include<cstdio>
#include<iostream>
#define N 2000005
using namespace std;
int n,m,sz;
int root[N],ls[N],rs[N],v[N],deep[N];
void build(int &k,int l,int r){
if(!k)k=++sz;
if(l==r){v[k]=l;return;}
int mid=(l+r)>>1;
build(ls[k],l,mid);
build(rs[k],mid+1,r);
}
void modify(int l,int r,int x,int &y,int pos,int val){
y=++sz;
if(l==r){v[y]=val;deep[y]=deep[x];return;}
ls[y]=ls[x];rs[y]=rs[x];
int mid=(l+r)>>1;
if(pos<=mid)
modify(l,mid,ls[x],ls[y],pos,val);
else modify(mid+1,r,rs[x],rs[y],pos,val);
}
int query(int k,int l,int r,int pos){
if(l==r)return k;
int mid=(l+r)>>1;
if(pos<=mid)return query(ls[k],l,mid,pos);
else return query(rs[k],mid+1,r,pos);
}
void add(int k,int l,int r,int pos){
if(l==r){deep[k]++;return;}
int mid=(l+r)>>1;
if(pos<=mid)add(ls[k],l,mid,pos);
else add(rs[k],mid+1,r,pos);
}
int find(int k,int x){
int p=query(k,1,n,x);
return x==v[p]?p:find(k,v[p]);
}
int main(){
int f,k,a,b;
cin>>n>>m;
build(root[0],1,n);
for(register int i=1;i<=m;i++){
cin>>f;
if(f==1){
root[i]=root[i-1];
cin>>a>>b;
int p=find(root[i],a),q=find(root[i],b);
if(v[p]==v[q])continue;
if(deep[p]>deep[q])swap(p,q);
modify(1,n,root[i-1],root[i],v[p],v[q]);
if(deep[p]==deep[q])add(root[i],1,n,v[q]);
}else if(f==2){
cin>>k;root[i]=root[k];
}else if(f==3){
root[i]=root[i-1];
cin>>a>>b;
int p=find(root[i],a),q=find(root[i],b);
if(v[p]==v[q])cout<<1<<endl;
else cout<<0<<endl;
}
}
return 0;
}
又是熟悉的線段樹(貌似從主席樹開始就陰魂不散了),複雜度因線段樹而多加了一個log,但是以資料結構的標準資料範圍來說,這點複雜度仍然是極好的,加上讀入輸出優化後可以從300ms->40ms
親自手測。
rope大發好!!!!
#include<cstdio>
#include<algorithm>
#include<ext/rope>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
using namespace __gnu_cxx;
const int maxn=20000+10;
rope<int> *b[maxn];
int a[maxn];
int i,j,k,l,t,n,m,ans;
bool flag;
int getfa(int id,int x){
if (b[id]->at(x)==0) return x;
b[id]->replace(x,getfa(id,b[id]->at(x)));
return b[id]->at(x);
}
int main(){
flag=0;
scanf("%d%d",&n,&m);
fo(i,1,n) a[i]=0;
b[0]=new rope<int> (a,a+n+1);
fo(i,1,m){
b[i]=new rope<int> (*b[i-1]);
scanf("%d",&t);
if (t==1){
scanf("%d%d",&j,&k);
if (flag) j^=ans,k^=ans;
j=getfa(i,j);
k=getfa(i,k);
if (j!=k) b[i]->replace(k,j);
}
else if (t==2){
scanf("%d",&k);
if (flag) k^=ans;
b[i]=b[k];
}
else{
scanf("%d%d",&j,&k);
if (flag) j^=ans,k^=ans;
j=getfa(i,j);
k=getfa(i,k);
if (j!=k) ans=0;else ans=1;
printf("%d\n",ans);
}
}
}
由於這道題資料太水(zky大大別打我),所以還有一個加強連加強版。
BZOJ 3674
題目連線
什麼強制線上。。。這種管用的手段。。除了xor就沒有一點新意嗎?(作死吐槽)
迴歸主題,對於上一篇來說,反正都是非離線做法,轉個線上水水水!!!!
其實用類似於主席樹的方法應該可以硬鋼過這道題吧
程式碼就用上面的那一份改改就好了,這裡就不發出來了。
END
到這裡,可持久化並查集的三部曲就結束了,不知道大家發沒發現,這三篇都有一個共同特點?
圖片都是博麗靈夢!!!
相關推薦
可持久化並查集(三)——從動態到可持久化
中已經可以算是一個偽可持久化了,但是對於歷史查詢等操作無能為力。。所以本篇重點介紹可持久化操作 BZOJ 3673 題目連線 這題不知道出題人什麼做法,但是程式碼很短的樣子 UPD:出題人用的是rope,即stl中的可持久化
可持久化並查集(外傳)——[按秩啟發式合併]
重新開坑 奉上最近覺得的神作(至少從小說與這首曲子來說是這樣的)。 之前寫到過可持久化並查集三部曲,現在想來,唯獨沒有提到按秩合併,在研習了啟發式合併後,決定重新為並查集寫一份外傳,記錄並查集的另一作用。 什麼是按秩合併,就小編來看,其實就是啟發式合併
洛谷P3402 【模板】可持久化並查集(可持久化線段樹,線段樹)
std 樹節點 https case 深度 build eof spa 復雜度 orz TPLY 巨佬,題解講的挺好的。 這裏重點梳理一下思路,做一個小小的補充吧。 寫可持久化線段樹,葉子節點維護每個位置的fa,利用每次只更新一個節點的特性,每次插入\(logN\)個節點,
【BZOJ3674】可持久化並查集加強版 (可持久化並查集裸題)
又到暑假了,頹了好些天的蒟蒻決定再次開始寫部落格了。由於本蒟蒻太弱了,連NOI都沒資格參加,只好在家裡看NOI的同步賽題嗚嗚嗚~。第一題一看就是可持久化並查集裸題,可是蒟蒻沒寫過。。。所以
並查集(UnionFind)
為什麼引入並查集 並查集的引入是為了解決動態連通問題。在動態連通場景中解決給定的兩節點,判斷它們是否連通,如果連通,不需要給出具體路徑。(而對於要給出具體路徑的問題可以採用DFS). 什麼是並查集 在電腦科學中,並查集是一種樹型的資料結構,其保持著用於處理一些不相交集合(Di
並查集(模板)
(luogu 3367) 模板如下: #include <bits/stdc++.h> #define ll long long #define N 10005 using namespace std; int fa[N]; int findf(int x) { if(x=
並查集(等式)
等式 描述 有n個變數和m個“相等”或“不相等”的約束條件,請你判定是否存在一種賦值方案滿足所有m個約束條件。 輸入 第一行一個整數T,表示資料組數。 接下來會有T組資料,對於每組資料: 第一行是兩個整數n,m,表示變數個數和約束條件的個數。 接下來m行,每行三
並查集與帶權並查集(轉)
並查集 並查集是一個很高效演算法,理解起來也很簡單,寫起來更簡單。 ①fat[i] = i; ②找到一個點的祖先 int findfat(int x) { if(fat[x] == x) return x; return fi
並查集(親戚)
#include<iostream>using namespace std;int N ;int parent[100]; void UFset() //初始化{for(int i = 0;i < N;i++) parent[i]=-1;} int
NOJ-1593:並查集(一)-西工大演算法
#include <stdio.h> #include <stdlib.h> int n, m; int p[1005]; int find(int i); int m
數據結構_並查集(轉載)
target blog 隨機 輸出 無法 增加 輸出結果 還需 class 一、問題引入 原題:杭電hdu1232暢通工程 題意:首先在地圖上給你若幹個城鎮,這些城鎮都可以看作點,然後告訴你哪些對城鎮之間是有道路直接相連的。最後要解決的是整幅圖的連通性問題。比如隨意給
並查集(UnionFind)技巧總結
## 什麼是並查集 在電腦科學中,並查集是一種樹型的資料結構,用於處理一些不交集(Disjoint Sets)的合併及查詢問題。有一個聯合-查詢演算法(Union-find Algorithm)定義了兩個用於此資料結構的操作: - Find:確定元素屬於哪一個子集。它可以被用來確定兩個元素是否屬於同一子集
可持久化專題(三)——可持久化並查集
前言 要學可持久化並查集,必須先會可持久化陣列。 簡介 可持久化並查集應該是一個挺實用的資料結構(例如NOI2018Day1T1中就有它的身影)。 它主要建立於可持久化陣列的基礎之上(而可持久化陣列
BZOJ 3674 可持久化並查集加強版(主席樹變形)
als ret desc scan sync scanf ops 只需要 ica 3673: 可持久化並查集 by zky Time Limit: 5 Sec Memory Limit: 128 MB Submit: 2515 Solved: 1107 [
【BZOJ4025】二分圖(可撤銷並查集+線段樹分治)
題目: BZOJ4025 分析: 定理:一個圖是二分圖的充要條件是不存在奇環。 先考慮一個弱化的問題:保證所有邊出現的時間段不會交叉,只會包含或相離。 還是不會?再考慮一個更弱化的問題:邊只會出現不會消失。 當加邊的時候,若\((u,v)\)不連通:一定不會構成奇環,將它加入。 若\(
可持久化並查集加強版 BZOJ 3674
log 歷史 clear 必須 new 路徑壓縮 都是 return 父節點 http://www.lydsy.com/JudgeOnline/problem.php?id=3674 3674: 可持久化並查集加強版 Time Limit: 15 Sec Memory
uvalive 4730王國kingdom(並查集+線段樹)
[0 ++ char == tac sum data 操作 input ?? 題意:有T組測試數據。每組數據的N表示有N個城市,接下來的N行裏每行給出每一個城市的坐標(0<=x,y<=1000000),然後有M(1<M<200000)個操作,操作
(並查集狀態壓縮)CodeForces - 469D Two Sets
queue == 劃分 查詢 sample 在那 des elong equal Little X has n distinct integers: p1,?p2,?...,?pn. He wants to divide all of them into two sets
POJ 1988 Cube Stacking(並查集+路徑壓縮)
trac ref nio space == using n) scan 累加 題目鏈接:id=1988">POJ 1988 Cube Stacking 並查集的題目 【題目大意】 有n個元素,開始每一個元素自己 一棧。有兩種操作,將含有元素
HDU 1198 Farm Irrigation(並查集+位運算)
another org des clas accepted som using red wan Farm Irrigation Time Limit : 2000/1000ms (Java/Other) Memory Limit : 65536/32768K (Java