题目大意:给定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; }