ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[HDU-6756]Finding a MEX

2021-01-02 18:02:46  阅读:200  来源: 互联网

标签:HDU const int 6756 sqrt readin ++ sqn Finding


题目

传送门

题解

方法一、\(\mathcal O(n\sqrt n\log n)\)

考虑到数据范围 \(n\le 100000\),在分块可以接受的范围内,同时,如果我们暴力修改,肯定和点的度有关,那么我们不妨将点的度进行分块:

  • 对于度数小于等于 \(\sqrt n\) 的点,修改的时候暴力改,询问的时候暴力问;
  • 对于度数大于 \(\sqrt n\) 的点,首先这种点最多 \(\sqrt n\) 个,那么我们用一种数据结构对于这不超过 \(\sqrt n\) 个点进行维护,而这个数据需要支持单点修改和求 \(\text {mex}\),不难想到 \(\tt BIT\);

这个算法,在第一种情况下是 \(\mathcal O(n\sqrt n)\),但是由于处理大点的情况使用了 \(\tt BIT\) 进行维护,所以最终复杂度 \(\mathcal O(n\sqrt n \log n)\),在 \(T\le 10\) 的情况下居然还可以过,这个 \(T\) 怕不是假的......

方法二、\(\mathcal O(n\sqrt n)\)

第一种方法的 \(\log n\) 在于使用了 \(\tt BIT\),我们可以考虑怎么不用 \(\tt BIT\) 对于大点进行维护.

考虑值域分块,每 \(\sqrt n\) 个数分成一块,对于每个块维护这个块中出现了多少不同的数字,询问的时候从小到大枚举块,在第一个不满的块中再暴力找.

这样,修改 \(\mathcal O(q\sqrt n)\)(小块暴力改),询问 \(\mathcal O(q\sqrt n)\)(大块暴力枚举每个块),时间复杂度就变成了 \(\mathcal O(q\sqrt n)\).

# include <cstdio>
# include <set>
# include <algorithm>
# include <vector>
using namespace std;
namespace Elaina{
    # define rep(i,l,r) for(int i=l, i##_end_ = r; i <= i##_end_; ++ i)
    # define fep(i,l,r) for(int i=l, i##_end_ = r; i >= i##_end_; -- i)
    # define fi first
    # define se second
    # define Endl putchar('\n')
    # define writc(x, c) fwrit(x), putchar(c)
    // # define int long long
    typedef long long ll;
    typedef pair<int, int> pii;
    typedef unsigned long long ull;
    typedef unsigned int uint;
    template<class T>inline T Max(const T x, const T y){return x < y ? y : x;}
    template<class T>inline T Min(const T x, const T y){return x < y ? x : y;}
    template<class T>inline T fab(const T x){return x < 0 ? -x : x;}
    template<class T>inline void getMax(T& x, const T y){x = Max(x, y);}
    template<class T>inline void getMin(T& x, const T y){x = Min(x, y);}
    template<class T>T gcd(const T x, const T y){return y ? gcd(y, x % y) : x;}
    template<class T>inline T readin(T x){
        x=0; int f = 0; char c;
        while((c = getchar()) < '0' || '9' < c) if(c == '-') f = 1;
        for(x = (c ^ 48); '0' <= (c = getchar()) && c <= '9'; x = (x << 1) + (x << 3) + (c ^ 48));
        return f ? -x : x;
    }
    template<class T>void fwrit(const T x){
        if(x < 0)return putchar('-'), fwrit(-x);
        if(x > 9)fwrit(x / 10); putchar(x % 10 ^ 48);
    }
}
using namespace Elaina;

const int maxn = 1e5;
const int sqn = 320;


int n, m, q;
int a[maxn + 5];

struct BLOCK{
    int bcnt[sqn + 5];
    int cnt[maxn + 5];
    inline void clear(){
        rep(i, 0, n) cnt[i] = 0;
        rep(i, 0, sqn) bcnt[i] = 0;
    }
    inline void inser(const int x){
        if(++ cnt[x] == 1) ++ bcnt[x / sqn];
    }
    inline void delet(const int x){
        if(-- cnt[x] == 0) -- bcnt[x / sqn];
    }
    inline int query(){
        int elai = 0;
        while(bcnt[elai] == sqn) ++ elai;
        int i = elai * sqn;
        while(cnt[i]) ++ i;
        return i;
    }
}block[sqn + 5];

struct edge{int to,nxt;
    edge(const int T = 0, const int N = 0) : to(T), nxt(N){}
}e[maxn * 2 + 5];
int tail[maxn + 5], d[maxn + 5], ecnt;
inline void add_edge(const int u, const int v){
    ++ d[u], ++ d[v];
    e[++ ecnt] = edge(v, tail[u]); tail[u] = ecnt;
    e[++ ecnt] = edge(u, tail[v]); tail[v] = ecnt;
}
/** @brief record the adjacent big point*/
vector<int>G[maxn + 5];
/** @brief the id of big point*/
int id[maxn + 5];
int idcnt;

inline void init(){
    n = readin(1), m = readin(1);
    ecnt = idcnt = 0;
    rep(i, 1, n) tail[i] = d[i] = id[i] = 0, G[i].clear();
    rep(i, 1, n) a[i] = Min(readin(1), n);
    int u, v;
    rep(i, 1, m){
        u = readin(1), v = readin(1);
        add_edge(u, v);
    }
    rep(u, 1, n) if(d[u] > sqn){
        id[u] = ++ idcnt;
        block[id[u]].clear();
        for(int i = tail[u]; i; i = e[i].nxt){
            G[e[i].to].push_back(u);
            block[id[u]].inser(a[e[i].to]);
        }
    }
}

int bucket[sqn + 5];

signed main(){
    int T = readin(1);
    while(T --){
        init();
        int opt, x, val;
        q = readin(1);
        while(q --){
            opt = readin(1), x = readin(1);
            /** @brief the option to modify*/
            if(opt == 1){
                val = Min(readin(1), n);
                /** @brief just need to modify the adjacent bit point*/
                for(int i = 0, sz = G[x].size(); i < sz; ++ i){
                    block[id[G[x][i]]].delet(a[x]);
                    block[id[G[x][i]]].inser(val);
                }
                a[x] = val;
            } else{
                /** @brief if this is a big point*/
                if(id[x]) writc(block[id[x]].query(), '\n');
                else{
                    rep(i, 0, sqn + 1) bucket[i] = 0;
                    for(int i = tail[x]; i; i = e[i].nxt)
                        ++ bucket[Min(a[e[i].to], sqn + 1)];
                    rep(i, 0, sqn + 1) if(!bucket[i]){
                        writc(i, '\n'); break;
                    }
                }
            }
        }
    }
    return 0;
}

标签:HDU,const,int,6756,sqrt,readin,++,sqn,Finding
来源: https://www.cnblogs.com/Arextre/p/14223450.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有