【loj2341】【WC2018】即时战略

题目

交互题;

一开始所有点都是黑的,你需要把所有点变白;

explore(u,v)会将u到v路径上的第二个点变白;

一开始只有1号点是白色的,你需要让所有点变白;

对于一条链次数限制\(O(n+log \ n)\),普通的树次数限制\(O(n \ log \ n)\) ;

题解

  • orz yww

  • Part 1

  • 白色区间一定是一条链,记录左右端点;

  • 先假设新点在左边用左端点扩展,如果explore出重复的点,则说明在右边换右端点;

  • 这样一直扩展,最坏\(O(2n)\),期望\(O(n+log \ n)\)

  • 浪费次数其实可以看成从头开始的上升子序列的长度,考虑\(n\)放在哪里:

  • 期望$E_n= 1 + \sum_{i=0}^{n-1} \frac{1}{n} E_{i} -> E_n = E_{n-1}+\frac{1}{n} $  

  • 那么有两边就乘二,再随机一下每次默认的方向就乘二分之一还是log的;

  • Part 2

  • 只需要找到已知树上的离新点最近的点;

  • 可以用在LCT上跳,均摊\(n \ log \ n\),也可以在动态点分树上跳,严格\(n \log n\)

  • 我只会写LCT,LCT需要维护链顶和链底标号;

  • (不知道该如何描述.....建议看看rk1的代码)

    #include<bits/stdc++.h>
    #include "rts.h"
    #define il inline 
    using namespace std;
    const int N=300010;
    int vis[N],p[N],fa[N],ch[N][2],rev[N],L[N],R[N];
    il bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}//
    il bool isch(int x,int y){return ch[x][0]==y||ch[x][1]==y;}//
    il int findrt(int x){while(!isrt(x))x=fa[x];return x;}//
    il void mfy(int x){
      swap(ch[x][0],ch[x][1]);
      swap(L[x],R[x]);
      rev[x]^=1;
    }//
    il void pushdown(int x){
      if(rev[x]){
          if(ch[x][0])mfy(ch[x][0]);
          if(ch[x][1])mfy(ch[x][1]);
          rev[x]^=1;
      }
    }
    il 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]];   
    }//
    il void rotate(int x){
      int y=fa[x],z=fa[y];
      if(!isrt(y))ch[z][ch[z][1]==y]=x;
      int l=ch[y][1]==x,r=l^1;
      fa[x]=z;fa[y]=x;fa[ch[x][r]]=y;
      ch[y][l]=ch[x][r];ch[x][r]=y;
      pushup(y);pushup(x);
    }//
    void push(int x){
      static int sta[N],top;
      while(!isrt(x))sta[++top]=x,x=fa[x];
      sta[++top]=x;
      while(top)pushdown(sta[top--]);
    }//
    il void splay(int x){
      push(x);
      for(int y,z;!isrt(x);rotate(x)){
          y=fa[x],z=fa[y];
          if(!isrt(y))rotate( (ch[y][0]==x)^(ch[z][0]==y) ? x : y );
      }
    }//
    il void access(int x){
      for(int y=0;x;y=x,x=fa[x]){
          splay(x);
          ch[x][1]=y;
          pushup(x);
      }
    }//
    il void mkrt(int x){access(x);splay(x);mfy(x);}//
    il void link(int x,int y){fa[y]=x;}//
    il void solve(int n){
      int a[2]={1,1};
      for(int i=2;i<=n;++i){
          int u=p[i];if(vis[u])continue;
          int x=rand()%2,v=explore(a[x],u);
          if(vis[v])x^=1,v=explore(a[x],u);
          vis[v]=1;while(v!=u)vis[v=explore(v,u)]=1;
          a[x]=u;
      }
    }//
    void play(int n,int T,int typ){
      srand(23333323);
      for(int i=1;i<=n;++i)p[i]=i;
      random_shuffle(p+2,p+n+1);
      if(typ==3){solve(n);return;}
      vis[1]=1;
      for(int i=1;i<=n;++i)L[i]=R[i]=i;
      for(int i=2,lst=1;i<=n;++i){
          int u=p[i],v;
          lst=findrt(1);
          if(vis[u])continue;
          while(lst!=u){
              v=explore(lst,u);
              pushdown(lst);
              if(!vis[v])vis[v]=1,link(lst,v),lst=v;
              else if(v==R[ch[lst][0]])lst=ch[lst][0];
              else if(v==L[ch[lst][1]])lst=ch[lst][1];
              else lst=findrt(v);
          }
          //mkrt(lst); mkrt会被卡操作常数
          access(lst);
      }
      return ;
    }//

转载于:https://www.cnblogs.com/Paul-Guderian/p/10827067.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值