首页 > 代码库 > [BZOJ1455]罗马游戏-斜堆/左偏树-并查集(+数据生成器)

[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]罗马游戏-斜堆/左偏树-并查集(+数据生成器)