zoukankan      html  css  js  c++  java
  • 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;
            }
        }
    }
  • 相关阅读:
    windows下安装mysql-5.7.11-winx64
    memset库函数
    [转]全面解析《嵌入式程序员应该知道的16个问题》
    Cent OS 7 下 Redis 5.0.5 安装与配置
    SVN+TortoiseSVN的Windows版安装和配置
    工具和环境--目录(随时更新)
    Linux安装和配置Nodejs和NPM
    Windows10命令提示符窗口大小导致执行效率不同问题
    Windows安装Nodejs和npm以及创建项目
    WebStorm 2019.3.2安装与配置
  • 原文地址:https://www.cnblogs.com/liyexin/p/12945149.html
Copyright © 2011-2022 走看看