power oj 2825: 拔河大赛(并查集)

Description 

一年一度的西科拔河比赛要到了,比赛要求每只队伍的人数不超过cc人。qwy希望从ACM集训队选择尽可能多的人组成一支队伍去参加比赛。

众所周知,ACM集训队人数众多,每个队员不一定认识其他所有队员。程序猿是一种群居动物,他们不希望和不认识的人一起活动(如果A认识B,B认识C,那么可以认为A认识C)。如果A不认识B,那么A和B都不希望和对方组队参赛,并且程序猿希望和所有他认识的人一起参赛。集训队现在有nn个程序猿,编号1−n1−n。qwy现在有一张关系表,表上有mm条关系,每条关系包含两个整数XiXi和YiYi,表示XiXi和YiYi认识。现在qwy想知道,在每个人数限制cc下,他能派出的人数最多的队伍的信息,即队伍的人数和队长(队中编号最大的程序猿)编号。

Input 

Output 

对每个询问c,输出一行。 如果没有队伍可以选择输出-1。 如果有选择,输出最优选择下的队伍信息,即队伍人数和队伍中队长的编号。 如果有多个选择,输出队长编号最大的那个队伍的信息。

6 3 4 1 3 3 2 5 6 0 1 2 3

-1 1 4 2 6 3 3

Hint 

对于第一个样例,只能分为三个队伍:{1,2,3},{4},{5,6}. 第一个询问0,qwy并不能找到一支队伍,人数小于等于0,所以输出-1。 第二个询问1,只能找到{4}这个队伍,队伍信息为(1,4)即1个人,其中队长编号为4。 第三个询问2,输出队伍{5,6}的信息。 第四个询问3。输出队伍{1,2,3}的信息。

PS:这是一个典型的并查集的题,但是因为询问次数很多,所以要预处理,或者后面用二分查找找答案。下面给出两种代码:

结构体保存+二分查找:

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=2e5+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
struct node
{
    int x,i;
    bool friend operator<(node a,node b)
    {
        if(a.x==b.x)
            return a.i<b.i;
        return a.x<b.x;
    }
}a[maxn];
int root[maxn];
int find(int x)
{
    if(x==root[x])
        return x;
    return root[x]=find(root[x]);
}
void un(int x,int y)
{
    int x1=find(x),y1=find(y);
    if(x1!=y1)
        root[min(x1,y1)]=max(x1,y1);
}
int er(int l,int r,int c)
{
    int mid;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(a[mid].x<=c&&a[mid+1].x>c)
            break;
        if(a[mid].x>c)
            r=mid-1;
        else
            l=mid+1;
    }
    return mid;
}
int main()
{
    int m,n,q;
    cin>>n>>m>>q;
    for(int i=1;i<=n;i++)
        root[i]=i;
    for(int i=0;i<m;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        un(x,y);
    }
    me(a,0);
    for(int i=1;i<=n;i++)
    {
        a[find(i)].x++;
        a[find(i)].i=find(i);
    }
    sort(a+1,a+n+1);
    while(q--)
    {
        int c;scanf("%d",&c);
        int x=er(1,n,c);
        if(!a[x].x||a[x].x>c)
            printf("-1\n");
        else
            printf("%d %d\n",a[x].x,a[x].i);
    }
    return 0;
}

map记录+lower_bound

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=2e5+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
typedef long long ll;
using namespace std;
int root[maxn],pos[maxn],val[maxn];
void inct(int n)
{
    for(int i=1;i<=n;i++)
        root[i]=i,val[i]=1;
}
int find(int x)
{
    if(x==root[x])
        return x;
    return root[x]=find(root[x]);
}
void un(int x,int y)
{
    int x1=find(x),y1=find(y);
    if(x1!=y1)
    {
        root[min(x1,y1)]=max(x1,y1);
        val[max(x1,y1)]+=val[min(x1,y1)];
    }
}
int main()
{
    int m,n,q;
    cin>>n>>m>>q;
    inct(n);
    for(int i=0;i<m;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        un(x,y);
    }
    map<int,int>s;
    int l=0;
    for(int i=1;i<=n;i++)
    {
        if(root[i]==i)
           {
               pos[l++]=val[i];
               s[val[i]]=i;
           }
    }
    sort(pos,pos+l);
    while(q--)
    {
        int c;scanf("%d",&c);
        int x=lower_bound(pos,pos+l,c)-pos;
        if(pos[x]==c)
            printf("%d %d\n",pos[x],s[pos[x]]);
        else if(x<1)
            printf("-1\n");
        else
            printf("%d %d\n",pos[x-1],s[pos[x-1]]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41292370/article/details/81869484
今日推荐