D. Multiple Testcases(并查集)

http://codeforces.com/contest/1342/problem/D

题意:

给出n个数 ∈ [ 1 , k ] \in[1,k] [1,k],要分到最少的集合。
每个集合满足大于等于 i ∈ [ 1 , k ] i\in[1,k] i[1,k]的数最多 c i c_i ci个。

解析:

我们贪心去塞集合,从大到小。

对于每种数 i i i,我们分两种情况

  • 如果 i i i的数量不够,则下次不会到这个点了,所以 f a [ i ] = i − 1 fa[i]=i-1 fa[i]=i1。且当下会去找 i − 1 i-1 i1
  • 如果当前的数量已经到达 c i c_i ci,则马上找比 i i i小的 j j j,使得 c j > c i c_j>c_i cj>ci

第一次这样用并查集,现想的比较累。。。

代码:

/*
 *  Author : Jk_Chen
 *    Date : 2020-04-26-23.02.11
 */
#include
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<"> "<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=2e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
    while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
    while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
    if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/

struct Uni{
    int num;
    int tmp[maxn];
    int operator[](int idx)const{
        return tmp[idx];
    }
    int& operator[](int idx){
        return tmp[idx];
    }
    void push(int x){
        tmp[++num]=x;
    }
    void init(){
        sort(tmp+1,tmp+1+num);
        num=unique(tmp+1,tmp+1+num)-tmp-1;
    }
    int idx(int val){
        return lower_bound(tmp+1,tmp+1+num,val)-tmp;
    }
}U;
/*_________________________________________________________unique*/


vector<int>V[maxn];
int c[maxn];
int ct[maxn];

int nex[maxn];
int fa[maxn];
int fin(int p){return fa[p]==p?p:fa[p]=fin(fa[p]); }

int main(){
    int n=rd,k=rd;
    rep(i,1,n){
        int a=rd;
        U.push(a);
        ct[a]++;
    }
    rep(i,1,k){
        c[i]=rd;
    }
    U.init();
    rep(i,1,U.num){
        c[i]=c[U.tmp[i]];
    }
    c[0]=1e9;
    rep(i,1,U.num){
        if(c[i]==c[i-1])nex[i]=nex[i-1];
        else nex[i]=i-1;
        fa[i]=i;
    }

    int res=n;
    int id=0;
    while(res){
        id++;
        int p=fin(U.num);
        while(p){
            while(p&&V[id].size()<c[p]&&ct[U.tmp[p]]){
                V[id].pb(U.tmp[p]);
                ct[U.tmp[p]]--;
                res--;
                if(ct[U.tmp[p]]==0){
                    fa[p]=p-1;
                }
            }
            if(V[id].size()>=c[p])
                p=fin(nex[p]);
            else
                p=fin(p-1);
        }
    }
    printf("%d\n",id);
    rep(i,1,id){
        printf("%d ",V[i].size());
        for(auto P:V[i]){
            printf("%d ",P);
        }
        puts("");
    }
    return 0;
}

/*_________________________________________________________end*/

你可能感兴趣的:(D. Multiple Testcases(并查集))