【BZOJ】3673: 可持久化并查集 by zky & 3674: 可持久化并查集加强版(可持久化线段树)

http://www.lydsy.com/JudgeOnline/problem.php?id=3674

http://www.lydsy.com/JudgeOnline/problem.php?id=3673

双倍经验啦啦啦。。

给主席树换了个名称果然高大上。。。

首先要可持久化并查集其实就是可持久化数组。。。

那么因为数组的形式是这样的$P[x]$,那么我们用一种数据结构实现查找x返回对应的$P[x]$即可啦啦啦。

然后那么我所学的可持久化目前只有主席树QAQ哪天去写写fhqtreap。。。

所以用主席树查找下标x,然后在叶子中维护父亲。

然后就完了

#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <ext/rope>
using namespace std;
typedef long long ll;
#define rep(i, n) for(int i=0; i<(n); ++i)
#define for1(i,a,n) for(int i=(a);i<=(n);++i)
#define for2(i,a,n) for(int i=(a);i<(n);++i)
#define for3(i,a,n) for(int i=(a);i>=(n);--i)
#define for4(i,a,n) for(int i=(a);i>(n);--i)
#define CC(i,a) memset(i,a,sizeof(i))
#define read(a) a=getint()
#define print(a) printf("%d", a)
#define dbg(x) cout << (#x) << " = " << (x) << endl
#define error(x) (!(x)?puts("error"):0)
#define rdm(x, i) for(int i=ihead[x]; i; i=e[i].next)
inline const int getint() { int r=0, k=1; char c=getchar(); for(; c<‘0‘||c>‘9‘; c=getchar()) if(c==‘-‘) k=-1; for(; c>=‘0‘&&c<=‘9‘; c=getchar()) r=r*10+c-‘0‘; return k*r; }

const int N=2*1e5+10;
struct node { int l, r, f; }t[N*100];
int cnt, root[N], n;

void update(int l, int r, int &x, int pos, int f) {
	t[++cnt]=t[x]; x=cnt;
	if(l==r) { t[x].f=f; return; }
	int mid=(l+r)>>1;
	if(pos<=mid) update(l, mid, t[x].l, pos, f);
	else update(mid+1, r, t[x].r, pos, f);
}
int ask(int l, int r, int x, int pos) {
	if(l==r) return t[x].f;
	int mid=(l+r)>>1;
	if(pos<=mid) return ask(l, mid, t[x].l, pos);
	else return ask(mid+1, r, t[x].r, pos);
}
int P(int x, int y) { return ask(1, n, x, y); }
int un(int &x, int a, int b) { update(1, n, x, a, b); return b; } // union p(a)=y
int find(int &x, int y) { int f=P(x, y); return f==y?y:un(x, y, find(x, f)); }
int main() {
	read(n); int m=getint(), la=0;
	for1(i, 1, n) update(1, n, root[0], i, i);
	for1(i, 1, m) {
		int c=getint();
		root[i]=root[i-1];
		if(c==1) {
			int x=getint(), y=getint(); x^=la; y^=la;
			int fx=find(root[i], x), fy=find(root[i], y);
			if(fx!=fy) un(root[i], fx, fy);
		}
		else if(c==2) root[i]=root[getint()^la];
		else {
			int x=getint(), y=getint(); x^=la; y^=la;
			int fx=find(root[i], x), fy=find(root[i], y);
			printf("%d\n", la=(fx==fy));
		}
	}
	return 0;
}

  


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<n,m<=2*10^5

Input

Output

Sample Input

5 6
1 1 2
3 1 2
2 1
3 0 3
2 1
3 1 2

Sample Output

1
0
1

HINT

Source

出题人大SB++

时间: 2024-10-06 16:47:47

【BZOJ】3673: 可持久化并查集 by zky & 3674: 可持久化并查集加强版(可持久化线段树)的相关文章

BZOJ 3673 可持久化并查集 by zky &amp;&amp; 3674 可持久化并查集加强版

题目大意:维护一种数据结构实现可持久化并查集. 思路:利用可持久化线段树实现可持久化数组维护可持久化并查集.(不知道3674哪里加强了... CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define RANGE 8000010 #define MAX 200200 using namespace std; struct SegTree

BZOJ 3123 SDOI 2013 森林 可持久化线段树+启发式合并

题目大意:给出一个森林,每个节点都有一个权值.有若干加边操作,问两点之间路径上的第k小权值是多少. 思路:这题和COT1比较像,但是多了连接操作.这样就只能暴力合并连个树.启发式合并会保证时间复杂度不至于太大.然后就是用可持久化线段树维护一个树的信息,按照dfs序来建树,每个节点的可持久化链的参考版本就是它父亲的版本.之后利用权值线段树可区间加减的特性,用f[x] + f[y] - f[lca] - f[father[lca]]来计算权值. CODE: #include <cstdio> #i

[您有新的未分配科技点]可,可,可持久化!?------可持久化线段树普及版讲解

最近跑来打数据结构,于是我决定搞一发可持久化,然后发现--一发不可收啊-- 对于可持久化数据结构,其最大的特征是"历史版本查询",即可以回到某一次修改之前的状态,并继续操作:而这种"历史版本查询"会衍生出其他一些强大的操作. 今天,我们主要讲解可持久化线段树.其实,它的另外一个名字"主席树"似乎更加为人所知(主席%%%). 主席树与普通的线段树相比,多出来的操作是在修改时复制修改的一条链,这个操作的过程大概长下面这样. 至于为什么要这样做-- 对

【BZOJ 3674】可持久化并查集加强版&amp;【BZOJ 3673】可持久化并查集 by zky 用可持久化线段树破之

最后还是去掉异或顺手A了3673,,, 并查集其实就是fa数组,我们只需要维护这个fa数组,用可持久化线段树就行啦 1:判断是否属于同一集合,我加了路径压缩. 2:直接把跟的值指向root[k]的值破之. 3:输出判断即可. 难者不会,会者不难,1h前我还在膜这道题,现在吗hhh就当支持下zky学长出的题了. 3673: #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=ge

BZOJ 3673: 可持久化并查集 by zky

3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 2084  Solved: 941[Submit][Status][Discuss] Description n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0<n,m<=2*10^4 Input Output Sample Input 5 6

BZOJ 3673 可持久化并查集 by zky 可持久化并查集

题目大意:给定n个集合,提供三种操作: 1.合并a,b所在集合 2.回到第k次操作之后的状态 3.询问a,b是否在同一集合 可持久化并查集0.0 实现方式是用可持久化线段树实现可持久化数组维护可持久化并查集... 至于可持久化数组,每条路径上只有叶节点的位置的num域是有意义的,感觉无比浪费0.0 可是不这样还真没法维护0.0 合并时本来应该按照每个节点的深度之和维护,结果手残懒得写,只用siz维护了0.0 至于路径压缩,写了比不写慢0.0 还是不写了吧 #include<cstdio> #i

bzoj 3673 可持久化并查集

本质上是维护两个可持久化数组,用可持久化线段树维护. 1 /************************************************************** 2 Problem: 3673 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:76 ms 7 Memory:13780 kb 8 **********************************************************

【BZOJ-3673&amp;3674】可持久化并查集 可持久化线段树 + 并查集

3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status][Discuss] Description n个集合 m个操作操作:1 a b 合并a,b所在集合2 k 回到第k次操作之后的状态(查询算作操作)3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0<n,m<=2*10^4 Input Output Sample Input 5 6

bzoj3673可持久化并查集 by zky&amp;&amp;bzoj3674可持久化并查集加强版

bzoj3673可持久化并查集 by zky 题意: 维护可以恢复到第k次操作后的并查集. 题解: 用可持久化线段树维护并查集的fa数组和秩(在并查集里的深度),不能路径压缩所以用按秩启发式合并,可以使合并均摊复杂度为O(nlog2n).可持久化线段树实际上就是在更新节点时按主席树的插入方式新建一条路径(其实主席树就是可持久化权值线段树). 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm&g