• 【学习笔记】「JOISC 2017 Day 3」自然公园


    考虑对于一个点 x x x,找到它与当前连通块相连的所有边。我们希望通过 log ⁡ n \log n logn次询问确定一条边。

    一般的策略是将数划分成两个大小相同集合然后去找答案,这里考虑 二分前缀,因为将点按照 D F N DFN DFN序排序,可以保证这段前缀构成一个连通块。那么固定根节点 r r r,询问 x x x r r r是否可达,找到最小的前缀 y y y,就能确定 x x x y y y之间有一条边。将 y y y删掉后处理剩下的连通块即可,这部分有 m log ⁡ n m\log n mlogn次。

    然后考虑怎么确定 x x x。发现可以通过类似的方法确定从 x x x到连通块的路径上的一个点 y y y,那么先递归处理 y y y,直到不存在这样的 y y y时再把 x x x加入连通块即可。注意到每个节点只会被找到一次,这部分复杂度 n log ⁡ n n\log n nlogn

    总次数 ( n + m ) log ⁡ n (n+m)\log n (n+m)logn

    #include
    #include "park.h"
    #define fi first
    #define se second
    #define pb push_back
    #define ll long long
    using namespace std;
    mt19937 gen(114514);
    int vs[1405],vs2[1405],state[1405],n;
    vector<int>nums;
    vector<int>G[1405];
    void dfs(int u,int topf){
        nums.pb(u);
        for(auto v:G[u]){
            if(v==topf||vs2[v])continue;
            dfs(v,u);
        }
    }
    int work(int p,int rt){
        nums.clear(),dfs(rt,-1);
        memset(vs,0,sizeof vs);
        for(auto e:nums)vs[e]=1;vs[p]=1;
        if(Ask(min(p,rt),max(p,rt),vs)==0)return -1;
        int l=1,r=nums.size(),res=0;
        while(l<=r){
            int mid=l+r>>1;
            memset(vs,0,sizeof vs);
            for(int i=0;i<mid;i++)vs[nums[i]]=1;vs[p]=1;
            if(Ask(min(p,rt),max(p,rt),vs))res=mid,r=mid-1;
            else l=mid+1;
        }
        int tmp=nums[res-1];vs2[tmp]=1;
        Answer(min(p,tmp),max(p,tmp));
        for(auto u:G[tmp]){
            if(vs2[u]==0)work(p,u);
        }return tmp;
    }
    int get(int x){
        int l=1,r=n,res=0;
        while(l<=r){
            int mid=l+r>>1;
            for(int i=0;i<mid;i++){
                vs[i]=(state[i]==1||state[i]==0);
            }
            for(int i=mid;i<n;i++){
                vs[i]=(state[i]==1);
            }
            vs[x]=1;
            if(Ask(0,x,vs)){
                res=mid,r=mid-1;
            }
            else{
                l=mid+1;
            }
        }return res-1;
    }
    void solve(int x){
        state[x]=2;int y;
        while(1){
            memset(vs2,0,sizeof vs2);
            y=work(x,0);
            if(~y){
                state[x]=1;
                G[x].pb(y),G[y].pb(x);
                return;
            }
            solve(get(x));
        }
    }
    void Detect(int T,int N){
        n=N;
        state[0]=1;
        for(int i=1;i<n;i++){
            if(state[i]==0)solve(i);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
  • 相关阅读:
    图论:图的相关定义
    英语学习笔记36——Where ... ?
    AD18原理图转Candence SPB17.4
    图片base64说明
    Kubernetes亲和性学习笔记
    springboot+easyExcel
    医疗健康产品展:联影医疗
    【高等数学重点题型篇】——不定积分
    GIN框架:自定义结构体到出JSON格式
    VSCode官方历史版本下载
  • 原文地址:https://blog.csdn.net/cqbzlydd/article/details/132794739