zoukankan      html  css  js  c++  java
  • LG P5473 [NOI2019] I 君的探险

    Description

    时隔半年,I 君的商店终于开不下去了,他决定转让商店,做一名探险家去探索未知的广阔世界。

    根据古书记载,他在一个大荒漠的腹地找到了未知文明创造的地下宫殿,宫殿由 $N$ 个大型洞穴和 $M$ 条连接这些洞穴的双向通路构成。I 君能借助古书分辨所处的洞穴,但书中并没有记录 $M$ 条通路的连接结构,因此他难以搜寻传说中藏在宫殿里的无尽财宝。

    不过现在 I 君发现了一个神秘机关,通过它可以获知宫殿的信息,I 君决定利用这个机关来得到宫殿的连接结构,请你来协助他。

    地下宫殿可以抽象成一张 $N$ 个点、$M$ 条边的无向简单图(简单图满足任意两点之间至多存在一条直接相连的边),洞穴从 $0 sim n - 1$ 编号。目前你并不知道边有哪些。

    每个洞穴都拥有一个光源,光源有开启、关闭两种状态,只有当光源处于开启状态时它所在的洞穴才会被照亮。初始时所有的光源都处于关闭状态,而光源的状态只能用I 君发现的神秘机关改变。更具体的,使用神秘机关可以进行如下四种操作:

    1. 向机关给定一个编号 $x$,机关将会改变$x$ 号洞穴,以及与$x$ 号洞穴有通路直接相连的洞穴的光源状态。即原来开启的光源将会关闭;原来关闭的光源将会开启。

    2. 向机关给定一个编号 $x$,机关将会显示当前$x$ 号洞穴光源的状态。

    3. 向机关给定两个编号 $x, y$,表示你确定有一条连接 $x$ 号洞穴与 $y$ 号洞穴的通路,并让机关记录。

    4. 向机关给定一个编号 $x$,机关将会判断与 $x$ 号洞穴相连的通路是否都已被记录。

    机关在完成上一次操作后才能进行下一次操作。机关不能随意使用,因此每种操作的使用次数都有限制,分别为 $L_m, L_q, M, L_c$。你的任务是,编写一个程序,帮助 I 君决定如何合理利用神秘机关,从而正确地找到这 $M$ 条通路。

    Solution

    需要写多个部分分

    第一个部分分:每次改变某个点的状态,枚举其它点状态是否变化,若变化则有连边

    第三个部分分:保证数据为一棵树,整体二分,每次改变$[l,mid]$的状态,如果询问范围中的点满足$leq mid$或状态改变则连边在分治范围左侧

    第四个部分分:保证数据为一条链,二进制分组,每次改变二进制位某一位为1的所有点的状态,如果询问范围中的点只满足该位为1或状态改变中的一个,那么它相连的两个点的该位上的异或和为1,暴力查找0点所连的边,由0点开始向链的两侧扩展更新答案

    第六个部分分:类似第三个部分分,这次需要在一个随机的询问序列上进行整体二分,可以连好某个排列里向前连边是奇数的点,重复做几次即可

    其余的部分分可以归为第六个部分分

    #include "explore.h"
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<vector>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    void modify(int x);
    int query(int x);
    void report(int x,int y);
    int check(int x);
    namespace task1{
        int sta[505];
        void main(int n){
            for(int i=0;i<=n-2;i++){
                modify(i),sta[i]^=1;
                for(int j=i+1;j<=n-1;j++)if(sta[j]^query(j))sta[j]^=1,report(i,j);
            }
        }
    }
    namespace task3{
        int q[200005],q1[200005],q2[200005];
        void solve(int l,int r,int ql,int qr){
            if(ql>qr)return;
            if(l==r){
                for(int i=ql;i<=qr;i++)report(l-1,q[i]-1);
                return;
            }
            int mid=l+r>>1,tot1=0,tot2=0;
            for(int i=l;i<=mid;i++)modify(i-1);
            for(int i=ql;i<=qr;i++)
                if(q[i]<=mid||query(q[i]-1))q1[++tot1]=q[i];
                else q2[++tot2]=q[i];
            for(int i=l;i<=mid;i++)modify(i-1);
            for(int i=1;i<=tot1;i++)q[ql+i-1]=q1[i];
            for(int i=1;i<=tot2;i++)q[ql+tot1+i-1]=q2[i];
            solve(l,mid,ql,ql+tot1-1),solve(mid+1,r,ql+tot1,qr);
        }
        void main(int n){
            report(0,1);
            for(int i=3;i<=n;i++)q[i]=i;
            solve(1,n,3,n);
        }
    }
    namespace task4{
        int p[200005];
        void dfs(int k,int fa){
            if(!(fa^p[k]))return;
            report(k,fa^p[k]),dfs(fa^p[k],k);
        }
        void main(int n){
            for(int i=0;(1<<i)<n;i++){
                for(int j=0;j<n;j++)if(j>>i&1)modify(j);
                for(int j=0;j<n;j++)if((j>>i&1)^query(j))p[j]|=1<<i;
                for(int j=0;j<n;j++)if(j>>i&1)modify(j);
            }
            modify(0);
            for(int i=1;i<n;i++)if(query(i))report(0,i),dfs(i,0);
        }
    }
    namespace task6{
        int cnt,tot,id[200005],q[200005],sta[200005],q1[200005],q2[200005];
        bool vst[200005];
        vector<int>ve[200005];
        bool calc(int x){
            bool ret=query(id[x]-1);
            for(int i=0;i<ve[id[x]].size();i++)ret^=sta[ve[id[x]][i]];
            return ret;
        }
        void solve(int l,int r,int ql,int qr){
            if(ql>qr)return;
            if(l==r){
                for(int i=ql;i<=qr;i++)if(q[i]!=l)report(id[l]-1,id[q[i]]-1),ve[id[l]].push_back(id[q[i]]),ve[id[q[i]]].push_back(id[l]),--cnt;
                return;
            }
            int mid=l+r>>1;
            for(int i=l;i<=mid;i++)if(!vst[id[i]])modify(id[i]-1),sta[id[i]]=1;
            int tot1=0,tot2=0;
            for(int i=ql;i<=qr;i++)
                if(q[i]<=mid||calc(q[i]))q1[++tot1]=q[i];
                else q2[++tot2]=q[i];
            for(int i=l;i<=mid;i++)if(!vst[id[i]])modify(id[i]-1),sta[id[i]]=0;
            for(int i=1;i<=tot1;i++)q[ql+i-1]=q1[i];
            for(int i=1;i<=tot2;i++)q[ql+tot1+i-1]=q2[i];
            solve(l,mid,ql,ql+tot1-1),solve(mid+1,r,ql+tot1,qr);
        }
        void main(int n,int m){
            cnt=m;
            for(int i=1;i<=n;i++)id[i]=i;
            while(cnt){
                random_shuffle(id+1,id+n+1),tot=0;
                for(int i=1;i<=n;i++)if(!vst[id[i]])q[++tot]=i;
                solve(1,n,1,tot);
                if(cnt)for(int i=1;i<=n;i++)if(!vst[i]&&check(i-1))vst[i]=true;
            }
        }
    }
    void explore(int n,int m){
        if(n<=500)task1::main(n);
        else if(n%10==7)task3::main(n);
        else if(n%10==6)task4::main(n);
        else task6::main(n,m);
    }
    [NOI2019] I 君的探险
  • 相关阅读:
    八月十四日学习报告
    八月二十一学习报告
    八月二十三学习报告
    八月十七日学习报告
    八月二十二学习报告
    八月十六日学习报告
    八月十九学习报告
    八月二十学习报告
    八月十五日学习报告
    每日日报2020.11.4 1905
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14250421.html
Copyright © 2011-2022 走看看