POJ--2985 The k-th Largest Group(第K大组,带权并查集+树状数组+二分)

地址:http://poj.org/problem?id=2985

题意:

输入n,m。共n只猫,m组询问。

1,L,R。L号猫所在组和R号猫所在组合并

0,x。查询第x大组有几只猫。

解析:

理解了好久的说。。。最最重要的还是树状数组的本质要理解好,要不代码写再多也没用。

树状数组:c[i]表示所含人数在[i-lowbit(i)+1,i]的组有几个

hav[i]:表示i号猫所在组有几只猫

pr[i]:并查集

first:初始化:此代码是非常有利于理解这道题的。意思是:含有人数为1的组数有n组。

update(1,n);

1:当两个组L和R合并时,那么人数为hv[L]和hv[R]的组数都要-1。新组人数为:hv[L]+hv[R],+1。而且总组数--

            update(hv[f1],-1);
            update(hv[f2],-1);
            update(hv[f1]+hv[f2],1);
            pr[f2]=f1;
            hv[f1]+=hv[f2];
            all--;

2:询问时,把第k大转化为第n-k+1小。

接下来,就是二分了。md=(L+R)>>1。

getsum(md):人数为[md-lowbit(md)+1,md]的组有几个?是不是接近n-k+1?

以此类推~直到找到答案

总的AC代码,cin会超时

#include<iostream>
#include<cstdio>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int pr[maxn],hv[maxn],c[maxn];
int n,m;
int find(int x)
{
    if(x!=pr[x])
        return pr[x]=find(pr[x]);
        return x;
}
int lowbit(int x){
    return x&(-x);
}
void update(int id,int x)
{
    for(int i=id;i<=maxn;i+=lowbit(i))
        c[i]+=x;
}
int getsum(int x)
{
    int ans=0;
    for(int i=x;i>=1;i=i-lowbit(i))
        ans+=c[i];
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        pr[i]=i;
        hv[i]=1;
    }
    update(1,n);
    int all=n;
    while(m--)
    {
        int x;
        scanf("%d",&x);
        if(x==0)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            int f1=find(l);
            int f2=find(r);
            if(f1==f2)
                continue;
            update(hv[f1],-1);
            update(hv[f2],-1);
            update(hv[f1]+hv[f2],1);
            pr[f2]=f1;
            hv[f1]+=hv[f2];
            all--;
        }
        else
        {
            int y;
            scanf("%d",&y);
            y=all-y+1;
            int l=1,r=n;
            while(l<=r)
            {
                int md=(l+r)>>1;
                if(getsum(md)>=y)
                    r=md-1;
                else
                    l=md+1;
            //    cout<<l<<"-"<<r<<endl;
            }
            cout<<l<<endl;
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/liyexin/p/12945149.html