• 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 君的探险
  • 相关阅读:
    VS2008编写MFC程序--使用opencv2.4()
    November 02nd, 2017 Week 44th Thursday
    November 01st, 2017 Week 44th Wednesday
    October 31st, 2017 Week 44th Tuesday
    October 30th, 2017 Week 44th Monday
    October 29th, 2017 Week 44th Sunday
    October 28th, 2017 Week 43rd Saturday
    October 27th, 2017 Week 43rd Friday
    October 26th, 2017 Week 43rd Thursday
    October 25th, 2017 Week 43rd Wednesday
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14250421.html
Copyright © 2020-2023  润新知