[HNOI2012] 永无乡

前言

没啥好说的,练板子水博客

题目

洛谷

讲解

联通性并查集维护,合并两个区间以及回答询问有两个做法。

做法1 平衡树

直接启发式暴力单点插入即可。

做法2 线段树合并

当然是权值线段树,回答询问时直接在线段树上二分就行。

代码

C++14 O2

FHQ Treap 649ms 3.16MB
//12252024832524
#include <cstdio>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 100005;
const int MOD = 1e9 + 7;
int n,m;

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

struct FHQ_Treap
{
	int l,r,f,siz,val,ID,rd;
}t[MAXN];
void up(int x){t[x].siz = t[t[x].l].siz + t[t[x].r].siz + 1;}
void split(int now,int val,int &x,int &y)
{
	if(!now) {x = y = 0;return;}
	else
	{
		if(t[now].val <= val) 
		{
			x = now;
			split(t[now].r,val,t[now].r,y);
			t[t[now].r].f = x;
		}
		else
		{
			y = now;
			split(t[now].l,val,x,t[now].l);
			t[t[now].l].f = y;
		}
		up(now);//now!!! not x!!!
	}
}
int mge(int x,int y)
{
	if(!x || !y) return x|y;
	if(t[x].rd < t[y].rd)
	{
		t[x].r = mge(t[x].r,y); up(x);
		t[t[x].r].f = x;
		return x;
	}
	else
	{
		t[y].l = mge(x,t[y].l); up(y);
		t[t[y].l].f = y;
		return y;
	}
}
int qval(int now,int rk)
{
	while(t[now].f) now = t[now].f; 
	if(t[now].siz < rk) return -1;
	while(1)
	{
		if(t[t[now].l].siz + 1 == rk) return t[now].ID;
		if(t[t[now].l].siz >= rk) now = t[now].l;
		else rk -= t[t[now].l].siz+1,now = t[now].r; 
	}
}
int Rand(){return (1ll * rand() * rand() * rand() + rand()) % MOD;}
void unionSet(int u,int v)
{
	int x,y;
	while(t[u].f) u = t[u].f;
	while(t[v].f) v = t[v].f;
	if(u == v) return;
	if(t[u].siz < t[v].siz) swap(u,v);
	int S = t[v].siz;
	for(int i = 1;i <= S;++ i)
	{
		int R = v;
		v = mge(t[R].l,t[R].r);
		t[R].l = t[R].r = 0; t[R].siz = 1;
		split(u,t[R].val-1,x,y);
		u = mge(mge(x,R),y);
	}
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	srand(42523);
	n = Read(); m = Read();
	for(int i = 1;i <= n;++ i) t[i] = {0,0,0,1,(int)Read(),i,Rand()};//l,r,f,siz,val,ID,rd
	for(int i = 1;i <= m;++ i) unionSet(Read(),Read());
	for(int T = Read(); T ;-- T)
	{
		char c = getchar();
		while(c != 'B' && c != 'Q') c = getchar();
		if(c == 'B') unionSet(Read(),Read());
		else
		{
			int ID = Read();
			Put(qval(ID,Read()),'\n');
		}
	}
	return 0;
}
线段树合并 452ms 34.12MB
//12252024832524
#include <cstdio>
#include <cstring>
#include <algorithm>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 100005;
int n,m;

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

int f[MAXN];
int findSet(int x)
{
	if(x ^ f[x]) f[x] = findSet(f[x]);
	return f[x];
}
int rt[MAXN];
int ch[MAXN<<5][2],tot,siz[MAXN<<5],ans[MAXN<<5];
void up(int x)
{
	if(!x) return;
	siz[x] = siz[ch[x][0]] + siz[ch[x][1]];
}
void Build(int &x,int l,int r,int pos,int val)
{
	if(!x) x = ++tot;
	if(l == r) {siz[x] = 1;ans[x] = val;return;}
	int mid = (l+r) >> 1;
	if(pos <= mid) Build(ch[x][0],l,mid,pos,val);
	else Build(ch[x][1],mid+1,r,pos,val);
	up(x);
}
int mge(int x,int y)
{
	if(!x || !y) return x|y;
	ch[x][0] = mge(ch[x][0],ch[y][0]);
	ch[x][1] = mge(ch[x][1],ch[y][1]);
	siz[x] += siz[y];
	ans[x] = Max(ans[x],ans[y]);
	return x;
}
void unionSet(int u,int v)
{
	u = findSet(u); v = findSet(v);
	if(u == v) return;
	if(u > v) swap(u,v); f[v] = u;
	rt[u] = mge(rt[u],rt[v]);
}
void Query(int x,int l,int r,int rk)
{
	if(rk > siz[x]){Put(-1,'\n');return;}
	if(l == r){Put(ans[x],'\n');return;}
	int mid = (l+r) >> 1;
	if(siz[ch[x][0]] >= rk) Query(ch[x][0],l,mid,rk);
	else Query(ch[x][1],mid+1,r,rk-siz[ch[x][0]]);
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); m = Read();
	for(int i = 1;i <= n;++ i) Build(rt[i],1,n,Read(),i),f[i] = i;
	for(int i = 1;i <= m;++ i) unionSet(Read(),Read());
	for(int T = Read(); T ;-- T)
	{
		char c = getchar();
		while(c != 'B' && c != 'Q') c = getchar();
		int x = Read();
		if(c == 'Q') Query(rt[findSet(x)],1,n,Read());
		else unionSet(x,Read());
	}
	return 0;
}
posted @ 2021-09-06 11:58  皮皮刘  阅读(75)  评论(0编辑  收藏  举报