SDOI2019热闹又尴尬的聚会

P5361 [SDOI2019]热闹又尴尬的聚会

出题人用脚造数据系列

只要将\(p\)最大的只求出来,\(q\)直接随便rand就能过

真的是

我们说说怎么求最大的\(p\),这个玩意具有很明显的单调性的吧

直接二分一下\(p\)的值,然后将其和他所以相连的所有度数\(>=p\)加进去,

可能最后有一些的点的实际度数\(<=p\)

我们就把他的贡献减掉,再出现再减

每个点只会入队一次

数据太弱,\(q\)直接随机吧

时间复杂度\(O(T(nlogn+rand)\)

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cmath>
#include<queue>
#include<vector>
#pragma GCC optimize(2)
#define LL long long
#define mk make_pair
#define pii pair<int,int>
using namespace std;
const int N = 1e5 + 3;
const int M = 2e5 + 3;
struct edge{
    int to;
    int nxt;	
}e[M << 2];
int num[N];
int n,m,T,dis,tot;
int head[N],d[N],need[N];
bool book[N],gg[N];
vector <int> G1,G2;
int p,q;
inline char nc(){
    #define SIZE 100000
    static char buf[SIZE],*p1 = buf+SIZE,*pend = buf+SIZE;
    if(p1 == pend){
        p1 = buf;pend = buf+fread(buf,1,SIZE,stdin);
        if(p1 == pend) return -1;
    }
    return *p1++;
    #undef SIZE
}
inline int read(){
    int x = 0;int flag = 0;
    char ch = nc();
    while(!isdigit(ch)){
        if(ch == '-') flag = 1;
        ch = nc();
    }
    while(isdigit(ch)){
        x = (x<<1) + (x<<3) + (ch^'0');
        ch = nc();
    }
    if(flag) x = -x;
    return x;
}
inline void add(int x,int y){
    e[++tot].to = y;
    e[tot].nxt = head[x];
    head[x] = tot;
}
inline bool check(int mid){
    queue <int> qq;
    for(int i = 1;i <= n;++i){book[i] = 0;need[i] = 0;gg[i] = 0;}
    for(int i = 1;i <= n;++i)
        if(d[i] >= mid) qq.push(i);
    while(!qq.empty()){
        int k = qq.front();qq.pop();
        for(int i = head[k];i;i = e[i].nxt){
            int y = e[i].to;
            if(d[y] < mid) continue;
            need[y]++;
        }
    }
    for(int i = 1;i <= n;++i) if(need[i] < mid) qq.push(i);
    while(!qq.empty()){
        int k = qq.front();qq.pop();
        gg[k] = 1;
        for(int i = head[k];i;i = e[i].nxt){
            int y = e[i].to;
            if(d[y] < mid) continue;
            need[y]--;
            if(need[y] < mid && !gg[y]) gg[y] = 1,qq.push(y);
        }
    }
    bool flag = 0;
//	cout << mid << endl;
//		for(int i = 1;i <= n;++i) cout << need[i] << " ";cout << endl;
    for(int i = 1;i <= n;++i) if(!gg[i] && need[i] >= mid) flag = 1;
    if(flag){
        G1.clear();
        p = mid;
        for(int i = 1;i <= n;++i) if(need[i] >= mid) G1.push_back(i);
    }
    return flag;
}
inline int work(){
    int x;
    random_shuffle(num + 1,num + n + 1);
    int ans = 0;
    x = num[1];
    for(int i = 1;i <= n;++i) book[i] = 0,gg[i] = 0;
    for(int i = head[x];i;i = e[i].nxt){
        int y = e[i].to;
        book[y] = 1;
    }
    gg[x] = 1,book[x] = 1;
    //ans = 1;
    for(int i = 1;i <= n;++i){
        if(book[num[i]]) continue;
        book[num[i]] = 1;
        gg[num[i]] = 1;
        ans++;
        for(int j = head[num[i]];j;j = e[j].nxt){
            int y = e[j].to;
            if(book[y]) continue;
            book[y] = 1;
        }
    }
    if(ans) ans++;
    return ans;
}
int main(){


    T = read();
    //cout << 1 << endl;
    while(T--){
        n = read(),m = read();
        for(int i = 1;i <= n;++i) num[i] = i;
        tot = 0;
        for(int i = 1;i <= n;++i) head[i] = 0,d[i] = 0;
        for(int i = 1;i <= m;++i){
            int x = read(),y = read();
            add(x,y);
            add(y,x);
            d[x]++,d[y]++;
        }
        //continue; 
        int l = 1,r = n,ans = 1;
        while(l <= r){
            int mid = (l + r) >> 1;
        //	cout << mid << endl;
            if(check(mid)) ans = mid,l = mid + 1;
            else r = mid - 1;	
        }
    //	cout << p <<endl; 
    //	continue;
        while(1){//cout << "GG" << endl;
            q = work();
            if(p >= n / (q + 1) && q >= n / (p + 1)){
                G2.clear();
                for(int i = 1;i <= n;++i)if(gg[i]) G2.push_back(i);
                break;
            }
        }
    //	printf("p:%d q:%d\n",p,q);
        printf("%d ",(int)G1.size());
        for(int i = 0;i < (int)G1.size();++i) printf("%d ",G1[i]);printf("\n");
        printf("%d ",(int)G2.size());
        for(int i = 0;i < (int)G2.size();++i) printf("%d ",G2[i]);printf("\n");
    }	
    return 0;	
}
posted @ 2019-05-11 10:54  wyxdrqcccc  阅读(265)  评论(0编辑  收藏  举报