zoukankan      html  css  js  c++  java
  • LG P6541 [WC2018]即时战略

    Description

    小 M 在玩一个即时战略 (Real Time Strategy) 游戏。不同于大多数同类游戏,这个游戏的地图是树形的。也就是说,地图可以用一个由 $n$ 个结点,$n - 1$ 条边构成的连通图来表示。这些结点被编号为 $1 sim n$。

    每个结点有两种可能的状态:「已知的」或「未知的」。游戏开始时,只有 $1$ 号结点是已知的。
    在游戏的过程中,小 M 可以尝试探索更多的结点。具体来说,小 M 每次操作时需要选择一个已知的结点 $x$,和一个不同于 $x$ 的任意结点 $y$(结点 $y$ 可以是未知的)。然后游戏的自动寻路系统会给出 $x$ 到 $y$ 的最短路径上的第二个结点 $z$,也就是从 $x$ 走到 $y$ 的最短路径上与 $x$ 相邻的结点。此时,如果结点 $z$ 是未知的,小 M 会将它标记为已知的。

    这个游戏的目标是:利用至多 $T$ 次探索操作,让所有结点的状态都成为已知的。然而小 M 还是这个游戏的新手,她希望得到你的帮助。

    为了让游戏过程更加容易,小 M 给你提供了这个游戏的交互库,具体见「任务描述」和「实现细节」。
    另外,小 M 也提供了一些游戏的提示,具体见题目的最后一节「提示」。

    Solution

    做法一:

    用LCT维护已经探索过的点,维护每一个点的前驱和后继,随机选择扩展某个点,假设$t= ext{explore}( ext{rand()}, ext{now})$,其中now初始时是LCT的根

    会有以下几种情况:1.$t$是now的前驱或后继,这个时候可以选择跳到Splay的左儿子或右儿子,相当于在Splay上做二分;2.$t$在其他Splay上,此时直接跳跃至该Splay的根;3.$t$从未被探索过,此时直接将其加入LCT

    不断重复以上过程直至探索到该随机值

    复杂度是$O(n log n)$的,因为以上过程实际上是LCT中access操作的逆序

    做法二:

    用点分树维护已经探索过的点,仍然随机扩展某个点,每求出一个$t$就在点分树上不断向上跳父节点直至知道其在当前now的什么方向,最终到叶子时会有新点加入点分树,此时直接加入,当点分树不平衡到一定程度时重构,类似替罪羊树

    时间复杂度$O(n log^2n)$

    //#include"rts.h"
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstdio>
    using namespace std;
    int p[300005],L[300005],R[300005],ch[300005][2],fa[300005],pos[2]={1,1};
    bool vst[300005];
    int explore(int ,int);
    bool nroot(int x){return ch[fa[x]][0]==x||ch[fa[x]][1]==x;}
    int getson(int x){return ch[fa[x]][1]==x;}
    void pushup(int x){
        L[x]=R[x]=x;
        if(ch[x][0])L[x]=L[ch[x][0]];
        if(ch[x][1])R[x]=R[ch[x][1]];
    }
    void rotate(int x){
        int y=fa[x],z=fa[y],b=getson(x),c=getson(y),a=ch[x][!b];
        if(nroot(y))ch[z][c]=x;
        fa[x]=z,ch[x][!b]=y,fa[y]=x,ch[y][b]=a;
        if(a)fa[a]=y;
        pushup(y),pushup(x);
    }
    void splay(int x){
        while(nroot(x)){
            int y=fa[x];
            if(nroot(y))
                if(getson(y)==getson(x))rotate(y);
                else rotate(x);
            rotate(x);
        }
    }
    void access(int x){for(int y=0;x;x=fa[y=x])splay(x),ch[x][1]=y,pushup(x);}
    void link(int x,int y){fa[y]=x,pushup(x);}
    int find(int x){
        while(nroot(x))x=fa[x];
        return x;
    }
    void play(int n,int T,int dataType){
        for(int i=1;i<n;i++)p[i]=i+1;
        random_shuffle(p+1,p+n);
        if(dataType==3){
            for(int i=1;i<n;i++){
                int now=p[i],d=rand()&1;
                if(vst[now])continue;
                int t=explore(pos[d],now);
                if(vst[t])t=explore(pos[d^=1],now);
                while(t!=now)vst[t]=true,t=explore(t,now);
                vst[pos[d]=now]=true;
            }
        }
        else{
            for(int i=1;i<=n;i++)L[i]=R[i]=i;
            for(int i=1;i<n;i++){
                int now=p[i];
                if(vst[now])continue;
                int x=find(1);
                while(x!=now){
                    int t=explore(x,now);
                    if(t==R[ch[x][0]])x=ch[x][0];
                    else if(t==L[ch[x][1]])x=ch[x][1];
                    else if(!vst[t]){
                        while(t!=now)link(x,t),x=t,vst[x]=true,t=explore(x,now);
                        link(x,t),vst[t]=true,x=t;
                    }
                    else x=find(t);
                }
                access(x);
            }
        }
    }
    /*
    g++ grader.cpp my.cpp -o rts -O2
    */
    [WC2018]即时战略
  • 相关阅读:
    centos从安装到环境配置
    PHP获取上个月、下个月、本月的日期
    js判断是哪种浏览器和阻止页面加载
    jquery中attr和prop的区别
    php curl 提交 总结
    合并二维数组,并计算重复字段的平均值
    检测端口和URL状态码判断启动服务
    curl-URL语法传输工具
    HAproxy 2.1.3源码 编译问题
    HAproxy 负载均衡器
  • 原文地址:https://www.cnblogs.com/JDFZ-ZZ/p/14546100.html
Copyright © 2011-2022 走看看