2020杭电多校(一) Finding a MEX(分块)

比赛的时候根据数据范围马上猜出了是通过轻重点分块,但是在维护set的时候犯了一个nt错误

选择了插入邻边的权值去判断第一个未出现的答案,怎么想都觉得复杂度很高。

其实可以选择先插入所有得可能答案,然后对邻边影响得答案进行删除,这样set中得第一个元素就是答案。

这题复杂度保证得原因是,通过分块,对于边数大于1000的称为重点,去维护一个set,因为边总共只有1e5条,这样的点不会超过100个,并且只需要维护从0-度数这样长度的set就行

后面的值肯定不会影响答案。

对于轻点,只需要暴力枚举所有的边去暴力判断,因为轻点邻边不会超过1000条,所以复杂度也得到保证

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10;
const int mod=998244353;
vector<int> g[N];
set<int> s[N];
int in[N];
int num[110][N];
int id[N];
bool st[N];
int a[N];
vector<int> now[N];
int main(){
    ios::sync_with_stdio(false);
    int i;
    int t;
    cin>>t;
    while(t--){
        int n,m;
        cin>>n>>m;
        int i;
        for(i=1;i<=n;i++)
            cin>>a[i];
        for(i=1;i<=n;i++){
            g[i].clear();
            in[i]=0;
            now[i].clear();
        }
        int block=1000;
        for(i=1;i<=m;i++){
            int x,y;
            cin>>x>>y;
            g[x].push_back(y);
            g[y].push_back(x);
            in[x]++,in[y]++;
        }
        int cnt=0;
        for(i=1;i<=n;i++){
            if(in[i]>=block){
                id[i]=++cnt;//ÀëÉ¢»¯Ó³Éä
                int j;
                s[cnt].clear();
                for(j=0;j<=in[i];j++){
                    s[cnt].insert(j),num[cnt][j]=0;
                }
            }
        }
        for(i=1;i<=n;i++){
            int j;
            for(j=0;j<g[i].size();j++){
                int u=g[i][j];
                if(in[u]>=block){
                    if(a[i]<=in[u]){
                        if(++num[id[u]][a[i]]==1){
                            s[id[u]].erase(a[i]);
                        }
                        now[i].push_back(u);
                    }
                }
            }
        }
        int q;
        cin>>q;
        while(q--){
            int opt;
            cin>>opt;
            if(opt==1){
                int x,y;
                cin>>x>>y;
                for(auto tmp:now[x]){
                    if(y<=in[tmp]){
                        if(++num[id[tmp]][y]==1)
                            s[id[tmp]].erase(y);
                    }
                    if(a[x]<=in[tmp]){
                        if(--num[id[tmp]][a[x]]==0){
                            s[id[tmp]].insert(a[x]);
                        }
                    }
                }
                a[x]=y;
            }
            else{
                int x;
                cin>>x;
                if(in[x]>=block){
                    cout<<*s[id[x]].begin()<<endl;
                }
                else{
                    for(i=0;i<g[x].size();i++){
                        int v=g[x][i];
                        if(a[v]<=in[x]){
                            st[a[v]]=1;
                        }
                    }
                    int ans=0;
                    while(st[ans])
                        ans++;
                    cout<<ans<<endl;
                    for(i=0;i<g[x].size();i++){
                        int v=g[x][i];
                        if(a[v]<=in[x]){
                            st[a[v]]=0;
                        }
                    }
                }
            }
        }
    }
    return 0;
}
View Code

 

posted @ 2020-07-22 22:25  朝暮不思  阅读(425)  评论(4编辑  收藏  举报