杭电第一场1005 Finding a MEX 树上分块

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6756
题目大意:
有一个n点,m条边的无向图,每个点有一个权值。现在有两个操作:
1 x y:把x点的权值修改为y
2 x : 查询x的的邻接点的权值中没有出现的最小非负整数。

思路:前几天正好补了一个分块的题,今天就遇到了。
我们考虑按点的度数进行维护。
我们考虑用权值线段树去维护每个点的mex。

对于修改x:
我们去遍历它d[y]>sqrt(n)的邻接点,最多有sqrt(n)个,每个在线段树上修改,复杂度:O(sqrt(n) * logn)
对于查询x:
如果d[u]<=sqrt(n)那么我们暴力每个点查询就可以了。复杂度:O(sqrt(n))
如果d[u]>sqrt(n)那么我们直接在线段树查询就可以了,复杂度:O(sqrt(n) * logn)
如果就一直T到怀疑人生。这个地方用线段树常树太大。

我们考虑一些其他的维护方法:
1.树状数组(sqrt(n) * logn):二分结果,前缀和查询。因为添加是O(sqrt(n) * logn)和查询(logn * log n)是分开的,那么复杂度还是添加的:sqrt(n) * logn
2.树状数组 (sqrt(n) * logn):我们可以直接在树上二分,标程的做法
3.set(sqrt(n) * logn):保存没有被占用的点。添加为set中删除,删除为set中添加。
3.分块(sqrt(n)): 我们根据上面的复杂度分析可以知道如果数据结构修改是O(1),查询是O(sqrt(n)),那么总的复杂度就是O(n * sqrt(n))。

具体做法:
我们按权值分块,用laz数组维护这个块非o的数量。用桶记一下个数,O(1)修改
查询到每一块if laz[i]!=len, 说明这个块有没有被占用的,去块里找,复杂度:O(sqrt(n))

#include <bits/stdc++.h>
using namespace std;

int f[200015], d[200015];
vector<int> G[200015], son[200015], pos;
int vis[200015];
struct FK{
    vector<int> w[200015], laz[200015];
    int len;
    void init(int n){
        len=sqrt(n)+1;
        for(int i=1; i<=n; i++){
            w[i].clear(); w[i].resize(2*d[i]+5);
            laz[i].clear(); laz[i].resize(2*d[i]+5);
        }
        for(int i=1; i<=n; i++){
            if(d[i]>len){
                int siz=d[i]/len;
                for(int k=0; k<=siz; k++){
                    laz[i][k]=len;
                }
            }
        }
    }
    void up_data(int pos, int x, int y){//x->y
        if(x<=d[pos]){
            w[pos][x]--;
            if(w[pos][x]==0){
                laz[pos][x/len]++;
            }

        }
        if(y<=d[pos]){
            w[pos][y]++;
            if(w[pos][y]==1){
                laz[pos][y/len]--;
            }
        }
    }
    int qurey(int pos){
        int siz=d[pos]/len;
        int p=siz;
        for(int i=0; i<=siz; i++){
            if(laz[pos][i]){
                p=i; break;
            }
        }
        for(int i=len*p; i<len*(p+1); i++){
            if(!w[pos][i]){
                return i;
            }
        }
    }

}F;

int main(){

    int t; scanf("%d", &t);
    while(t--){
        int n, m, q, x, y, z; scanf("%d%d", &n, &m);
        for(int i=1; i<=n; i++){
            f[i]=d[i]=0;
            G[i].clear();
            son[i].clear();
        }
        for(int i=1; i<=n; i++){
            scanf("%d", &f[i]);
        }
        for(int i=1; i<=m; i++){
            scanf("%d%d", &x, &y);
            G[x].push_back(y);
            G[y].push_back(x);
            d[x]++, d[y]++;
        }
        for(int i=1; i<=n; i++){
            sort(G[i].begin(), G[i].end(), [](int &a, int &b){return d[a]<d[b];});
        }
        int len=sqrt(n)+1;
        F.init(n);
        for(int i=1; i<=n; i++){
            for(auto x: G[i]){
                if(d[x]>len){
                    son[i].push_back(x);
                }
            }
        }
        for(int i=1; i<=n; i++){
            for(auto x: son[i]){
                F.up_data(x, 1e5+5, f[i]);
            }
        }

        scanf("%d", &q);
        while(q--){
            scanf("%d%d", &x, &y);
            if(x==1){
                scanf("%d", &z);
                for(auto x: son[y]){
                    if(d[x]>len){
                        F.up_data(x, f[y], z);
                    }
                }
                f[y]=z;
            }
            else{
                if(d[y]>len){
                    for(auto x: son[y]){
                        F.up_data(x, 1e5+5, f[x]);
                    }
                    printf("%d\n", F.qurey(y));
                    for(auto x: son[y]){
                        F.up_data(x, f[x], 1e5+5);
                    }
                }
                else{
                    for(int i=0; i<G[y].size(); i++){
                        if(f[G[y][i]]<n+5){
                            pos.push_back(f[G[y][i]]);
                            vis[f[G[y][i]]]=1;
                        }
                    }
                    for(int i=0; i<=n+5; i++){
                        if(!vis[i]){
                            printf("%d\n", i);
                            break;
                        }
                    }
                    for(auto x: pos){
                        vis[x]=0;
                    }
                    pos.clear();
                }
            }
        }
    }

    return 0;
}
全部评论

相关推荐

点赞 收藏 评论
分享
牛客网
牛客企业服务