zoukankan      html  css  js  c++  java
  • 2020杭电多校第一场 hdu6756 Finding a MEX

    题目链接

    http://acm.hdu.edu.cn/showproblem.php?pid=6756

    题目大意

    给定 N 个带权点和 M 条边 , 其中第 i 个点的权值为 ai

    有 Q 次操作 , 每次操作有以下两种类型 :

    ①、将第 u 个点的权值修改为 x

    ②、查询与第 u 个点的相邻点集的 MEX

    解题思路 

    经典根号分治

    考虑把修改的复杂度提高以便降低查询的复杂度

    先将度数大于等于根号 N 的点设为重点 , 度数小于根号 N 的点设为轻点

    因为 M <= 1e5 , 所以重点数不超过 350 , 那么就可以对每个重点建立一个权值树状数组

    ①、对于轻点的查询直接暴力枚举与之相邻点的点集的MEX( 最多不超过 sqrt(n) 个)

    ②、对于重点的查询在树状数组上二分跑答案即可 ( 判断前缀权值和是否等于 mid ) 

    ③、对节点 u 的修改只要修改与其相邻重点的权值树状数组的权值 and a[u] 的值

    时间复杂度为 $Oleft( qleft( sqrt{n}+log n^{2} ight) ight) $

    为了防止爆空间 , bit 得使用 vector 动态建立( 注意 vector 开辟空间后要初始化 )

    AC_Code

    #include<bits/stdc++.h>
    #define rep(i,a,n) for (int i=a;i<=n;i++)
    #define int long long 
    using namespace std;
    const int N = 3e5 + 10 ;
    struct Edge{
        int nex , to;
    }edge[N << 1];
    int head[N] , TOT;
    void add_edge(int u , int v)
    {
        edge[++ TOT].nex = head[u] ;
        edge[TOT].to = v;
        head[u] = TOT;
    }
    vector<int>tree[N] , cnt[N] , vec[N];
    int n , m , q , sq;
    int a[N] , du[N] , zero[N] , vis[N];
    int lowbit(int x)
    {
        return x & (-x);
    }
    void add(int pos , int x , int id)
    {
        int up = du[id] + 5;
        while(pos < up)
        {
            tree[id][pos] += x;
            pos += lowbit(pos); 
        }
    }
    int get_sum(int pos , int id)
    {
        int res = 0;
        while(pos)
        {
            res += tree[id][pos];
            pos -= lowbit(pos);
        }
        return res;
    }
    void init(int n)
    {
        TOT = 0;
        rep(i , 1 , n) zero[i] = head[i] = du[i] = 0 , vec[i].clear();
    }
    void change(int u , int x)
    {
        if(!a[u]) for(auto i : vec[u]) zero[i] -- ;
        else
        {
            for(auto i : vec[u])
            {
                if(a[u] > du[i]) continue ;
                cnt[i][a[u]] -- ;
                if(!cnt[i][a[u]]) add(a[u] , -1 , i);
            }
        } 
        if(!x) 
        {
            for(auto i : vec[u]) zero[i] ++ ; 
            a[u] = x;
            return ; 
        } 
        for(auto i : vec[u])
        {
            if(x > du[i]) continue ;
            cnt[i][x] ++ ;
            if(cnt[i][x] == 1) add(x , 1 , i);
        }
        a[u] = x;
    }
    int query1(int u)
    {
        rep(i , 0 , du[u]) vis[i] = 0;
        for(int i = head[u] ; i ; i = edge[i].nex)
        {
            int v = edge[i].to ;
            if(a[v] > du[u]) continue ;
            vis[a[v]] ++ ;
        }
        rep(i , 0 , 330) if(!vis[i]) return i;
    }
    int query2(int u)
    {
        if(!zero[u]) return 0;
        int l = 1 , r = du[u] , res = du[u];
        while(l <= r)
        {
            int mid = l + r >> 1;
            if(get_sum(mid , u) < mid) r = mid - 1 , res = mid;
            else l = mid + 1;
        }
        return res;
    }
    signed main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0) , cout.tie(0);
        int t ;
        cin >> t;
        while(t --)
        {
            cin >> n >> m ;
            sq = sqrt(n);
            rep(i , 1 , n) cin >> a[i]; 
            rep(i , 1 , m)
            {
                int u , v;
                cin >> u >> v;
                add_edge(u , v) , add_edge(v , u);
                du[u] ++ , du[v] ++ ;
            }
            rep(u , 1 , n) 
            {
                for(int i = head[u] ; i ; i = edge[i].nex)
                {
                    int v = edge[i].to; 
                    if(du[v] >= sq) vec[u].push_back(v);
                }
            }
            rep(u , 1 , n)
            {
                if(du[u] < sq) continue ;
                tree[u].resize(du[u] + 10);
                cnt[u].resize(du[u] + 10);
                rep(j , 0 , du[u]) tree[u][j] = cnt[u][j] = 0;
                for(int i = head[u] ; i ; i = edge[i].nex)
                {
                    int v = edge[i].to ; 
                    if(a[v] > du[u]) continue ;
                    if(!a[v]) {zero[u] ++ ; continue ;}
                    cnt[u][a[v]] ++ ;
                    if(cnt[u][a[v]] == 1) add(a[v] , 1 , u);
                }
            }
            cin >> q; 
            while(q --)
            {
                int op , u , x;
                cin >> op;
                if(op == 1)
                {
                    cin >> u >> x ;
                    change(u , x);
                }
                else
                {
                    cin >> u;
                    if(du[u] <= sq) cout << query1(u) << '
    ';
                    else cout << query2(u) << '
    ';
                }
            }
            init(n);
        }
        return 0;
    }

     

  • 相关阅读:
    深入MVC模式概念
    Asp.NET MVC and Asp.NET WebForms Features
    JavaScript实现简单进度条
    数据分页技术(学习笔记)
    sql行列转换<转>
    全自动静态网页生成器(三)——发布第一个可用版本
    ASP.NET AJAX进度条
    不能远程访问Win7系统上的Sql 2005数据库
    水印及缩略图的C#实现
    无任何网络提供程序接受指定的网络路径解决方法
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/13375377.html
Copyright © 2011-2022 走看看