XTU-OJ 1384-大佬,带带我

文章讲述了在一个团队中,根据队员的能力值实施训练制度,同时考虑队员之间的不喜欢关系,通过邮件通信确定每个人能带多少人的问题。作者给出了一个算法来计算每个人能带的人数,利用快读和队列排序优化处理大量数据。
摘要由CSDN通过智能技术生成

大佬,带带我

题目描述

Eric决定在队里实行老队员带新队员的训练制度。Eric给队里的每个人都评估了一个能力值,如果A的能力值高于B的,那么A就可以带B。 但是每个人的都有自己的个性,可能会不喜欢某人,这样必然会影响训练的效果。所以,Eric要大家发邮件给他,告知不喜欢带哪些人,或者不喜欢被哪些人带。

现在,Eric给你一个任务,请计算一下,每个人能带的人的数量。

输入

只有一组样例,第一行是两个整数n(1≤n≤10000),m(0≤m≤n),分别表示队员的数量和收到的邮件数量。 第二行是n个整数,a1,a2,…,an,1≤ai≤109) 依次表示队员的能力值。 以后的m行,每行表示一个队员的邮件,第一个是一个整数i(1≤i≤n),表示第i个队员,第二个是一个整数k(1≤k≤n−1),表示他不喜欢的人的数量,以后的k个整数b1,b2,…,bk,表示不喜欢人的编号。

输入数据保证所有的邮件的发件人都是唯一的,其不喜欢人列表中也没有重复元素,也不会包含自己。 ∑mi=1ki≤106 , ki表示第i份邮件中不喜欢人的数量。

输出

输出一行,n个整数,为每个人能带的人的数量,之间用一个空格隔开,行尾无空格。

样例输入

5 3
10 3 10 4 15
1 1 2
5 3 1 2 3
4 1 5

样例输出

1 0 2 1 0

样例解释

1号,按能力值可以带2和4号,但是他不喜欢2号,所以只能带4号1个人。 2号,能力值最低,不能带任何人,所以是0个。 3号,按能力值可以带2和4号,他没有不喜欢谁,2和4号也都没有不喜欢他,所以他可以带2个人。 4号,按能力值可以带2号,两者没有不喜欢关系,所以4号可以带1个。 5号,按能力可以带1,2,3,4号,但是他不喜欢1,2,3号,4号又不喜欢他,所以他不能带任何人。

提示

巨大的输入量,请使用快读技术

解题思路:对照代码理解更方便

AC代码: 

#include <stdio.h>
#include <stdlib.h>

struct Point{
    int x,y;
} P[1000010];
int n,m,k,player1,player2,x0,y0,i,j,cnt;
int a[10010], find[10010], ans[10010];

int read()                                      // 快读
{
	char ch=getchar();int x=0,f=1;
	while(ch<'0' || ch>'9')	{if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}

int cmp1(const void *p1, const void *p2){
    return *(int *)p1 - *(int *)p2;
}
int cmp2(const void *p1, const void *p2){       // 结构体排序
    if (((Point *)p1)->x != ((Point *)p2)->x)
        return ((Point *)p1)->x - ((Point *)p2)->x;
    return ((Point *)p1)->y - ((Point *)p2)->y;
}

int main()
{
    n = read(); m = read();
    for (i = 1; i <= n; i ++)   {a[i] = read();find[i-1] = a[i];}
    qsort(find,n,4,cmp1);            // 对find升序排序,这样在find数组中,a[i]的值排第几位,就有几个人能力小于i 
    for (i = 1; i <= n; i ++)
    {
        for (j = 0; find[j] < a[i]; j ++);  // 找到有 j 个人 能力比 i 小
        ans[i] = j;                  // i 按理说可以带 j 个人 
    }

    P[0].x = -1; P[0].y = -1;        // 插入一个无效元素,方便50行 i=1时 情况处理。
    for (i = 1; i <= m; i ++)        // 记录 不喜欢的人
    {
        player1 = read();  k = read();
        for (j = 1; j <= k; j ++)
        {
            player2 = read();        // 把不喜欢的两人, 序号较小的放 x, 较大的放在 y. 以实现(x,y)=> (1,2)、(2,1) 都表示为(1,2)
            if (player1 < player2)  {P[cnt].x = player1; P[cnt].y = player2; ++cnt;}
            if (player2 < player1)  {P[cnt].x = player2; P[cnt].y = player1; ++cnt;}
        }
    }
    qsort(P,cnt+1,sizeof(Point),cmp2); // 结构体排序
    for (i = 1; i <= cnt; i ++)
    {
        if (P[i-1].x == P[i].x && P[i-1].y == P[i].y)   continue;   // 如果两人是第二次一起出现,跳过处理
        x0 = P[i].x; y0 = P[i].y;
        if (a[x0] > a[y0] && ans[x0] > 0)  {ans[x0] -= 1;}
        if (a[y0] > a[x0] && ans[y0] > 0)  {ans[y0] -= 1;}
    }
    for (i = 1; i < n; i ++)         // 依次输出最后结果
        printf("%d ",ans[i]);
    printf("%d\n",ans[n]);
    return 0;
}

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值