[BZOJ1455]罗马游戏-斜堆/左偏树-并查集(+数据生成器)
Posted SkyLYnf
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1455]罗马游戏-斜堆/左偏树-并查集(+数据生成器)相关的知识,希望对你有一定的参考价值。
Problem 遗产
题目大意
罗马皇帝很喜欢玩杀人游戏。 他的军队里面有n个人,每个人都是一个独立的团。最近举行了一次平面几何测试,每个人都得到了一个分数。 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻。他决定玩这样一个游戏。 它可以发两种命令: 1. Merger(i, j)。把i所在的团和j所在的团合并成一个团。如果i, j有一个人是死人,那么就忽略该命令。 2. Kill(i)。把i所在的团里面得分最低的人杀死。如果i这个人已经死了,这条命令就忽略。 皇帝希望他每发布一条kill命令,下面的将军就把被杀的人的分数报上来。(如果这条命令被忽略,那么就报0分)
Solution
写一个并查集维护每个人所在的团,一个died数组判断每个人有没有死掉。
在此基础之上对每一个团建一个左偏树/斜堆优化查询最小值的过程,支持合并。
对于每一个合并操作只要将两个斜堆合并即可。
挺简单的一个裸题。
Datamaker
这一题题目其实是有问题的。
如果分数范围为1~10000,那么1000000个人中会有非常多个人是重分的。
仔细思考一下我们就会知道,重分情况下罗马皇帝也不知道会杀谁。
所以数据合法情况下这题没有人能够AC,甚至标程也是错的。
所以我将分数范围调整为1~10000000且没有人会重分。
1 #include <ctime> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstdio> 5 6 #define MAXN 1000000 7 #define MAXP 10000000 8 #define MAXM 100000 9 10 bool get[MAXP]; 11 using namespace std; 12 13 int randint(){ 14 return ((long long)rand()*9971+rand())%1000007; 15 } 16 int main(){ 17 freopen("bzoj1455.in","w",stdout); 18 srand(time(NULL)); 19 printf("%d\n",MAXN); 20 for(int i=1;i<=MAXN;i++){ 21 int p=randint()%(MAXP-1)+1; 22 while(get[p]){ 23 p=randint()%(MAXP-1)+1; 24 } 25 printf("%d ",p); 26 get[p]=1; 27 } 28 printf("%d\n",MAXM); 29 for(int i=1;i<=MAXM;i++){ 30 if(rand()%2==0){ 31 printf("M "); 32 int x=randint()%(MAXN-1)+1,y=randint()%(MAXN-1)+1; 33 if(x==y)y++; 34 printf("%d %d\n",x,y); 35 }else{ 36 printf("K "); 37 printf("%d\n",randint()%(MAXN-1)+1); 38 } 39 } 40 }
AC Code
#include <iostream> #include <cstdio> using namespace std; struct soldier{ int fa,died,l,r,v; }a[1000010]; int n,m,x,y,nx,ny,p; char tsk[2]; int find(int x){ return (a[x].fa==x)?x:a[x].fa=find(a[x].fa); } int merge(int x,int y){ if(!x)return y; if(!y)return x; if(a[x].v>a[y].v)swap(x,y); a[x].r=merge(a[x].r,y); swap(a[x].l,a[x].r); return x; } int main(){ // freopen("bzoj1455.in","r",stdin); // freopen("bzoj1455.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i].v); for(int i=1;i<=n;i++)a[i].fa=i; scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%s",tsk); if(tsk[0]==‘M‘){ scanf("%d%d",&x,&y); if(!a[x].died&&!a[y].died){ nx=find(x),ny=find(y); if(nx!=ny)a[nx].fa=a[ny].fa=merge(nx,ny); } }else{ scanf("%d",&x); if(!a[x].died){ p=find(x); a[p].died=1; printf("%d\n",a[p].v); a[p].fa=merge(a[p].l,a[p].r); a[a[p].fa].fa=a[p].fa; }else printf("0\n"); } } }
以上是关于[BZOJ1455]罗马游戏-斜堆/左偏树-并查集(+数据生成器)的主要内容,如果未能解决你的问题,请参考以下文章