• uoj349 即时战略


    题意:这是一道交互题。交互库中有一棵树。一开始只有1节点已知。需要在T次询问内使得n个节点都已知。一次询问explore(x,y),返回从x到y路径上第一个点,并将返回点标记为已知。

    数据有区分。

    标程:

     1 #include<cstdio>
     2 #include<time.h>
     3 #include<algorithm>
     4 #include "rts.h"
     5 using namespace std;
     6 const int N=300005;
     7 int son[N][2],fa[N],L[N],R[N],vis[N],E[2],id[N],now,nxt,it;
     8 int is_rt(int x) {return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;}
     9 int ran() {return (int)(rand()/RAND_MAX+0.5);}
    10 void up(int x)
    11 {
    12     L[x]=R[x]=x;
    13     if (son[x][0]) L[x]=L[son[x][0]];//leftest 
    14     if (son[x][1]) R[x]=R[son[x][1]];//rightest 
    15 }
    16 void rot(int x)
    17 {
    18     int y=fa[x],z=fa[y],l=(son[y][1]==x),r=l^1;
    19     if (!is_rt(y)) son[z][(son[z][1]==y)]=x;
    20     fa[x]=z;fa[y]=x;fa[son[x][r]]=y;
    21     son[y][l]=son[x][r];son[x][r]=y;
    22     up(y);up(x);
    23 }
    24 void spl(int x)
    25 {
    26     for (int y;!is_rt(x);rot(x))
    27       if (!is_rt(y=fa[x])) 
    28         if (son[y][0]==x^son[fa[y]][0]==y) rot(x);else rot(y);
    29 }
    30 int find_rt(int x)
    31 {
    32     for (;!is_rt(x);x=fa[x]);
    33     return x;
    34 }    
    35 void accs(int x) {for (int t=0;x;t=x,x=fa[x]) spl(x),son[x][1]=t,up(x);}
    36 void ins(int x)
    37 {
    38     now=find_rt(1);
    39     while (!vis[x])
    40     {
    41         nxt=explore(now,x);
    42         if (nxt==R[son[now][0]]) now=son[now][0];//father 
    43         else if (nxt==L[son[now][1]]) now=son[now][1];//son
    44         else {//another splay 
    45             if (vis[nxt]) now=find_rt(nxt);//already have existed
    46             else vis[nxt]=1,fa[nxt]=now,now=nxt;//add a new point
    47         }
    48     }
    49     accs(x);
    50 }
    51 void play(int n,int T,int dataType)
    52 {
    53     srand(time(NULL));
    54     vis[1]=1;
    55         for (int i=1;i<=n;i++) id[i]=i;
    56     random_shuffle(id+2,id+n+1);
    57     if (dataType==3)//chain
    58     {
    59         now=explore(1,id[2]);vis[now]=1;
    60         E[0]=1;E[1]=now;
    61         for (int i=2;i<=n;i++)
    62           if (!vis[id[i]])
    63           {
    64                it=ran();now=explore(E[it],id[i]);//注意explore的顺序(u->v)
    65                if (!vis[now])//这一边 
    66                {
    67                    vis[E[it]=now]=1; 
    68                    while (E[it]!=id[i]) E[it]=explore(E[it],id[i]),vis[E[it]]=1;//记得更改范围指针
    69              }else {//另一边
    70                  it^=1;
    71                  while (E[it]!=id[i]) E[it]=explore(E[it],id[i]),vis[E[it]]=1;
    72              }
    73           }
    74         return;
    75     }
    76     for (int i=1;i<=n;i++) L[i]=R[i]=i;//初始化
    77     for (int i=2;i<=n;i++)
    78       if (!vis[id[i]]) ins(id[i]);
    79 }

    易错点:1.注意lct之前的初始化L[i]=R[i]=i。并且不用每找到一个点就splay,新加入一个点access更新保证复杂度即可。

    2.access不要写错,判定继续的条件应该是x而不是!is_rt(x)。

    3.链的情况要更新边界。

    技巧:可以用random_shuffle来避免一些数据的卡。

    题解:lct/动态点分树

    数据告诉我们:树T=nlogn,链T=n+logn.

    树:

    1.仿照CF772E的做法,可以通过点分来插入一个点。但不同的是,这不是一棵二叉树,在前向星上插入删除的复杂度太高,因此考虑动态点分树来支持动态加点。(然而我并不会写)

    2.点分的思想也就是对树二分。因此我们树链剖分后在重链上二分也可以得到一样的效果。由于有加点,用lct即可。用splay维护每一条重链,因为splay的高度的log级别的,从根开始跳splay上的节点完成二分。讨论一下返回的已知点在询问点的儿子/父亲/另一个splay上->是否已知。最后access(x)更新树的形态。O(nlogn)。

    链:

    维护一段连续的已知点[L,R],对于一个未知点x,如果explore(L,x)是未知点,那么往R方向扩展,反之在L方向扩展。

    每个点必定被explore一次O(n)。random第一次的询问是L还是R后,更改方向的次数期望是O(log n)或是说O(ln n)的。(证明:设E(n)表示扩展为长度为n的序列需要更改几次方向:E(n)=1+1/n*sigma(E[i])(i=[1,n-1])->E(n)-E(n-1)=1/n->E(n)=sigma(1/i)≈ln n)

    所以总的是O(n+log n)。

  • 相关阅读:
    nginx简单配置
    解决 eclipse出现 Address already in use: bind
    JavaScript 正则表达式学习
    RabbitMQ的介绍与spring整合
    RabbitMQ的安装与客户端的简单实用
    java中的break与continue
    书单
    (七)SpringBoot2.0基础篇- application.properties属性文件的解析及获取
    (六)SpringBoot2.0基础篇- MyBatis、Redis整合(JedisCluster集群连接)
    (五)SpringBoot2.0基础篇- Mybatis与插件生成代码
  • 原文地址:https://www.cnblogs.com/Scx117/p/8721251.html
Copyright © 2020-2023  润新知