永无乡「HNOI2012」

题意

每个数有一个排名,要求维护两种操作:

  1. \(x\)\(y\)所在的联通块连载一起。

  2. 查询\(x\)所在联通块的\(k\)小值。


思路

思路显然,并查集维护连通性,动态开点权值线段树合并维护查询。这道题污染了HNOI。

代码

#include <bits/stdc++.h>

using namespace std;

namespace StandardIO {

	template<typename T> inline void read (T &x) {
		x=0;T f=1;char c=getchar();
		for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
		for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
		x*=f;
	}
	template<typename T> inline void write (T x) {
		if (x<0) putchar('-'),x=-x;
		if (x>=10) write(x/10);
		putchar(x%10+'0');
	}

}

using namespace StandardIO;

namespace Solve {
	
	const int N=100001;
	
	int n,m,q;
	int val[N],trn[N];
	int f[N];
	int cnt;
	struct node {
		int lc,rc;
		int l,r,val;
	} tree[N*40];
	int root[N];
	
	inline void pushup (int pos) {
		tree[pos].val=tree[tree[pos].lc].val+tree[tree[pos].rc].val;
	}
	void build (int rt,int l,int r,int &pos) {
		if (!pos) pos=++cnt; 
		tree[pos].l=l,tree[pos].r=r,tree[pos].val=0;
		if (l==r) return tree[pos].val=(l==val[rt]),void();
		int mid=(l+r)>>1;
		if (val[rt]<=mid) build(rt,l,mid,tree[pos].lc);
		else build(rt,mid+1,r,tree[pos].rc);
		pushup(pos);
	}
	int query (int k,int pos) {
		if (tree[pos].l==tree[pos].r) return tree[pos].l;
		if (k<=tree[tree[pos].lc].val) return query(k,tree[pos].lc);
		return query(k-tree[tree[pos].lc].val,tree[pos].rc);
	}
	void Tmerge (int &x,int y) {
		if (!x) return x=y,void();
		if (!y) return;
		if (tree[x].l==tree[x].r) return tree[x].val+=tree[y].val,void();
		Tmerge(tree[x].lc,tree[y].lc),Tmerge(tree[x].rc,tree[y].rc);
		pushup(x);
	}
	inline int find (int x) {
		return (f[x]==x)?x:f[x]=find(f[x]);
	}
	inline void merge (int x,int y) {
		x=find(x),y=find(y);
		if (f[x]!=y) f[x]=y,Tmerge(root[y],root[x]);
	}
	void dfs (int now) {
		cout<<tree[now].l<<' '<<tree[now].r<<endl;
		if (tree[now].lc) cout<<"lc:",dfs(tree[now].lc);
		if (tree[now].rc) cout<<"rc:",dfs(tree[now].rc);
	}

	inline void MAIN () {
		read(n),read(m);
		for (register int i=1; i<=n; ++i) {
			read(val[i]),trn[val[i]]=i,f[i]=i,build(i,1,n,root[i]);
		}
		for (register int i=1; i<=m; ++i) {
			int x,y;
			read(x),read(y);
			merge(x,y);
		}
		read(q);
		while (q--) {
			char op;int x,y;
			cin>>op,read(x),read(y);
			if (op=='B') {
				merge(x,y);
			} else {
				if (tree[root[find(x)]].val<y) write(-1);
				else write(trn[query(y,root[find(x)])]);
				putchar('\n');
			}
		}
	}

}

int main () {
	Solve::MAIN();
}
posted @ 2019-08-24 18:03  Ilverene  阅读(147)  评论(0编辑  收藏  举报