BZOJ2733线段树合并

第一次写线段树合并
一开始完全自己yy板子写得特别丑

后来看到了别人的板子发现又简洁又好写

//Never Say Never until the very end. 
#include 
#include 
#define N 100050

using namespace std;

int tr[20*N],ls[20*N],rs[20*N],fa[N],root[N],ys[N],hash[N];
int n,m,cnt,v,ans;

int get(int x) { if (fa[x] == x) return x; else return (fa[x] = get(fa[x]));}

void build(int l,int r,int t) {
	tr[t]++;
	if (l == r) return ;
	int mid = (l + r) / 2;
	if (v <= mid) 
		ls[t] = ++cnt , build(l,mid,cnt);
	else 
		rs[t] = ++cnt , build(mid+1,r,cnt);
}

int merge(int x,int y) {
	if (x == 0 || y == 0) return x+y;
	ls[x] = merge(ls[x],ls[y]);
	rs[x] = merge(rs[x],rs[y]);
	tr[x] = tr[ ls[x] ] + tr[ rs[x] ];
	return x;
}

void query(int l,int r,int t,int k) {
	if (l == r) { ans = l; return ;}
	int mid = (l + r) / 2;
	if (tr[ ls[t] ] >= k) 
		query(l,mid,ls[t],k);
	else 
		query(mid+1,r,rs[t],k - tr[ ls[t] ]);
}

int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++) scanf("%d",&ys[i]) , hash[ys[i]] = i;
	//cnt = 1;
	for (int i=1;i<=n;i++) fa[i] = i;
	for (v=1;v<=n;v++) root[v] = cnt+1 , build(1,n,++cnt);
	for (int i=1;i<=m;i++) {
		int u,v;
		scanf("%d%d",&u,&v);
		u = ys[u];
		v = ys[v];
		if (get(u) != get(v)) {
			merge( root[ get(u) ] , root[ get(v) ] );
			fa[ get(v) ] = get(u);
		}
	}
	
	int q;
	scanf("%d",&q);
	for (int i=1;i<=q;i++) {
		char cmd[10]; int a,b;
		scanf("%s%d%d",cmd+1,&a,&b);
		a = ys[a];
		if (cmd[1] == 'B') {
			b = ys[b];
			if (get(a) != get(b)) {
				merge(root[ get(a) ] , root[ get(b) ]);
				fa[ get(b) ] = get(a);
			}
		} else {
			if (tr[ root[ get(a) ] ] < b) {printf("-1\n");continue;}
			query(1,n,root[ get(a) ] , b);
			printf("%d\n",hash[ans]);
		}
	}
	return 0;
}


你可能感兴趣的:(BZOJ2733线段树合并)