杭电 1512 Monkey King

题目大意:给定n个猴子,每个猴子都有一个体力值,开始他们都不认识,如果两个猴子不认识,那么他们各自都会找一个自己认识的最厉害的猴子,然后进行PK,两个猴子PK以后的力量值会减少一半,PK之后这两个猴子和他们所有的朋友都会相互认识,以后遇到了也不会PK,问每次PK以后,当前这个群体里力量最大的猴子的力量是多少。

由于是朋友圈,判断是否在一个圈子中必然会用到并查集,速度写出如下代码,果断TLE了,

代码:“

#include<cstdio>
#include<string>
#include<iostream>
#include<cstring>
#include<set>
//include<
//#include<>
using namespace std;

int monkey[100001];
int f[100001];
multiset<int,greater<int> >value[100001];//用set表示朋友圈中的体力值
int n,m;
int Find(int x)
{
    if(f[x]==x)
        return x;
    else
        return f[x]=Find(f[x]);
}
void unite(int x,int y)
{
    x=Find(x);
    y=Find(y);
    if(x==y)
        return ;
    f[y]=x;
}

int main()
{    
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
        {
            value[i].clear();
                scanf("%d",&monkey[i]);
                f[i]=i;
                
        }
        scanf("%d",&m);
        for(int k=0;k<m;k++)
        {
            int a,b;
            scanf("%d %d",&a,&b);
            
            int x=Find(a);
            int y=Find(b);
            if(value[a].empty())
                value[a].insert(monkey[a]);
            if(value[b].empty())
                value[b].insert(monkey[b]);
            if(x==y)
                printf("-1\n");
            else
            {
                multiset<int,greater<int> >::iterator it1,it2;
               // a=x;
               // b=y;
                it1=value[x].begin();
                it2=value[y].begin();
                int t1=(*it1)/2;
                int t2=(*it2)/2;
                value[x].erase(it1);
                value[x].insert(t1);
                value[y].erase(it2);
                value[y].insert(t2);
                unite(a,b);
            
                for(it2=value[y].begin();it2!=value[y].end();++it2)
                    value[x].insert(*it2);
                value[y].clear();
                printf("%d\n",*value[x].begin());
                
            }
        }
    }
    return 0;
}

之后才知道有左偏树这么个数据结构,查了一下,都是代码居多,不过看的不是很明白,建议大家看看这篇文章,写的清晰易懂,下载地址:

http://download.csdn.net/detail/xueerfei008/5804235

代码是参考的这个空间里的内容:http://hi.baidu.com/ofeitian/item/3db5a2ff8c4aca6c3c1485f7 这个帖子中只有代码,但是很容易看明白:


不过不明白,这个题为什么在while(~scanf("%d",&n),n)多一个,n就成了PE了,写成while(~scanf("%d",&n))就过了。可能0有别的数据吧,直接退出不太好。

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int N=110000;
int n,m,f[N];

struct node
{
	int l,r;
	int dis,val;
}LTree[N];

int Find(int x)
{
	if(x==f[x])
		return x;
	else
		return f[x]=Find(f[x]);
}

int Merge(int x,int y)
{
	if(x==0) return y;
	if(y==0) return x;
	//最大堆
	if(LTree[x].val<LTree[y].val)
		swap(x,y);
	LTree[x].r=Merge(LTree[x].r,y);
	int l,r;
	l=LTree[x].l;
	r=LTree[x].r;
	f[r]=x;
	//保证左边比右边大
	if(LTree[l].dis<LTree[r].dis)
		swap(LTree[x].l,LTree[x].r);

	if(LTree[x].r==0)
		LTree[x].dis=0;
	else
		LTree[x].dis=LTree[LTree[x].r].dis+1;
	return x;
}

int pop(int x)
{
	int l,r;
	l=LTree[x].l;
	r=LTree[x].r;
	f[l]=l;
	f[r]=r;
	LTree[x].l=LTree[x].dis=LTree[x].r=0;
	return Merge(l,r);
}

void deal(int x,int y)
{
	int fx,fy;
	fx=Find(x);
	fy=Find(y);
	if(fx==fy)
		printf("-1\n");
	else
	{
		LTree[fx].val>>=1;
		LTree[fy].val>>=1;

		int a=pop(fx);
		int b=pop(fy);

		a=Merge(a,fx);
		b=Merge(b,fy);

		a=Merge(a,b);
		printf("%d\n",LTree[a].val);
	}
}

int main()
{
	int num;
	while(~scanf("%d",&n))
	{
		memset(LTree,0,sizeof(LTree));
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&num);
			LTree[i].val=num;
			f[i]=i;
		}
		scanf("%d",&m);
		int a,b;
		for(int i=0;i<m;i++)
		{
			scanf("%d %d",&a,&b);
			deal(a,b);
		}
	}
	return 0;
}
	

这种高级数据结构今天会了,估计明天也就忘了,多多做些联系,多巩固才行。


你可能感兴趣的:(杭电,monkey,King,1512)