关闭

POJ2985 The k-th Largest Group(Splay)

标签: 平衡树
169人阅读 评论(0) 收藏 举报
分类:

有n组猫,m个操作。初始的时候每组猫有一只,有两种操作,可以把两组猫合并为一组,或者查询猫数第k多的组。

对于合并猫我们开一个并查集,检查那些已经在一个集合中的猫。首先在splay树中插入每组猫的数,当合并的时候,就从树中删去那两组猫,在插入它们的和。为了方便删除,在初始化的时候要插入0和n+1两个节点。

#include<cstdio>
#include<cctype>
#define MAXN 200010
void GET(int &t)
{
	char c;
	t = 0;
	do{c = getchar();}while(!isdigit(c));
	while(isdigit(c)){t = t*10+c-'0'; c = getchar();}
}
int fa[MAXN],sz[MAXN],cnt[MAXN],tot,root,ch[MAXN][2],v[MAXN],n,m,op,sat[MAXN],amount[MAXN];
int find(int x)
{
	if(sat[x] == x) return sat[x];
	else return sat[x] = find(sat[x]);
}
void update(int x)
{
	sz[x] = sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];
}
void rotate(int x)
{
	int y = fa[x],z = fa[y],f = (ch[y][1]==x);
	ch[y][f] = ch[x][!f];
	if(ch[y][f]) fa[ch[y][f]] = y;
	ch[x][!f] = y,fa[y] = x;
	fa[x] = z;
	if(z) ch[z][ch[z][1]==y] = x;
	update(y);
}
void splay(int x,int goal)
{
	for(int y; (y=fa[x])!=goal; rotate(x))
	{
		int z = fa[y];
		if(z != goal)
		{
			if((ch[z][0]==y)==(ch[y][0]==x)) rotate(y);
			else rotate(x);
		}
	}
	if(goal == 0) root = x;
	update(x);
}
void insert(int val)
{
	int x = root,y = 0,f = 0;
	while(x != 0)
	{
		if(v[x] == val) {++cnt[x]; break;}
		f = v[x]<val;
		y = x;
		x = ch[x][f];
	}
	if(x == 0)
	{
		x = ++tot;
		v[x] = val;
		sz[x] = cnt[x] = 1;
		fa[x] = y;
		if(y) ch[y][f] = x;
	}
	splay(x,0);
}
int nxt(int val,bool flag)
{
	int x = root,y = 0;
	while(x != 0)
	{
		y = x;
		if(v[x] == val) break;
		x = ch[x][v[x]<val];
	}
	if((v[y]>val&&flag==1)||(v[y]<val&&flag==0)) return y;
	splay(y,0);
	int tmp = ch[y][flag];
	while(ch[tmp][!flag])
		tmp = ch[tmp][!flag];
	return tmp;
}
void del(int val)
{
	int x = nxt(val,0),y = nxt(val,1);
	splay(x,0);
	splay(y,x);
	int z = ch[y][0];
	if(z)
	{
		if(cnt[z] > 1)
		{
			cnt[z]--;
			splay(z,0);
		}
		else 
		{
			ch[y][0] = 0;
			cnt[z] = 0;
			splay(y,0);
		}
	}
}
int kth(int k)
{
	int y = root,x;
	if(k > sz[root]) return 0;
	while(1)
	{
		x = ch[y][1];
		if(sz[x]+cnt[y] < k)
		{
			k -= sz[x]+cnt[y];
			y = ch[y][0];
		}
		else if(sz[x]>=k) y = x;
		else return v[y];
	}
}
int main()
{
	GET(n);
	GET(m);
	insert(0);
	insert(n+1);
	for(int i = 1; i <= n; i++) sat[i] = i,insert(1),amount[i] = 1;
	int a,b,c;
	for(int i = 1; i <= m; i++)
	{
		GET(op);
		if(op)
		{
			GET(a);
			printf("%d\n",kth(a+1));
		}
		else
		{
			GET(a),GET(b);
			a = find(a);
			b = find(b);
			if(a == b) continue;
			del(amount[a]);
			del(amount[b]);
			c = amount[a]+amount[b];
			sat[b] = a;
			amount[a] = c;
			amount[b] = c;
			insert(c);
		}
	}
}


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:43242次
    • 积分:1601
    • 等级:
    • 排名:千里之外
    • 原创:121篇
    • 转载:2篇
    • 译文:0篇
    • 评论:4条
    最新评论