[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;
}