题目链接:

[WC2018]即时战略

题目大意:给一棵结构未知的树,初始时除1号点其他点都是黑色,1号点是白色,每次你可以询问一条起点为白色终点任意的路径,交互库会自动返回给你这条路径上与起点相邻的节点并且如果这个点为黑色则将它变为白色,要求在不多于给定次数的询问内使所有点变为白色。

大致思路为按一定顺序分别将n-1个点变为白点,为了防止被卡,需要对2~n的序列随机打乱再按打乱后的顺序逐个变白。

数据范围分为三种,分开讲解(假设当前要变白的点为x):

一、完全二叉树

这一部分比较简单,我们只需要按照一定顺序将每个点都变为白点即可。对于将每个点x变为白色的过程,因为可以确定上次询问的点一定是白点,所以我们每次询问以上次询问所返回的点为起点(第一次以根节点即1号点为起点),以x为终点询问,直到返回点为x为止。因为树高严格logn,询问次数为nlogn。

二、链

可以发现被变白的点一定是连续的一段,我们记录这一段的左右端点,每次先询问从一个端点到x的路径,如果返回点为白点说明x在1号点的另一边,再一直询问从另一个端点到x的路径并更新端点,直到x被变白为止。这样期望询问次数为n+logn(最大为2n),为了防止被卡,建议每次首先询问的端点左右交替,不要一直先询问左端点或右端点。

三、无限制

这一部分是本题的重点,题目要求的询问数上限为nlogn。可以发现白点一定组成一个联通块,对于每个待寻找的点,只要找到当前所有白点中与它相连的点即可。从完全二叉树的做法中我们可以得到启发:如果在寻找每个点的过程中只遍历到logn个节点,那么就能满足要求。而原树树高上限是O(n),无法在原树上直接寻找,但点分树保证树高为logn啊!我们每一次从点分树的根开始,假设当前走到的点为now,那么每次询问从now到x的路径,假设返回点为y,y一定是以now为分治中心时,now的一个子节点,而x一定是在y这个子树所表示的联通块中,我们只要下一次将now变为y这棵子树的分治中心再寻找就能使查找范围减小至少一半。因为时间复杂度上限不在查询上,所以对于每一次查找y这棵子树的分治中心可以直接在点分树上从y暴力往上爬,直到爬到点的父节点是now为止,这样可以减少存储的信息量(方便后边的重构)。如果对于一次询问返回点为黑点,那么需要将这个点插入到点分树中,我们直接将这个点连到当前now的下面即可。这样建出的点分树会很不平衡,我们像紫荆花之恋那道题一样设置一个平衡因子,每次插入后找到离根最近的不平衡点,对这个点在点分树上的子树进行点分治然后建出这棵子树真正的点分树,注意重构点可能是点分树的根,所以要记录点分树的根是谁。每次重构均摊O(logn^2),总时间复杂度为O(nlogn^2),询问次数为nlogn。

#include"rts.h"
#include<map>
#include<cmath>
#include<vector>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int tot;
int vis[300010];
int head[300010];
int to[600010];
int next[600010];
int f[300010];
int size[300010];
int mx[300010];
int root;
int num;
int id[300010];
int col[300010];
int l,r;
int now;
int point;
int rot;
vector<int>q[300010];
inline void add(int x,int y)
{
next[++tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void getroot(int x,int fa)
{
size[x]=1;
mx[x]=0;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
getroot(to[i],x);
size[x]+=size[to[i]];
mx[x]=max(mx[x],size[to[i]]);
}
}
mx[x]=max(num-size[x],mx[x]);
if(mx[x]<mx[root])
{
root=x;
}
}
void dfs(int x,int fa,int rt)
{
q[rt].push_back(x);
size[x]=1;
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]]&&to[i]!=fa)
{
dfs(to[i],x,rt);
size[x]+=size[to[i]];
}
}
}
void partation(int x,int fa)
{
vis[x]=1;
f[x]=fa;
q[x].clear();
dfs(x,0,x);
for(int i=head[x];i;i=next[i])
{
if(!vis[to[i]])
{
num=size[to[i]];
root=0;
getroot(to[i],0);
partation(root,x);
}
}
}
inline void insert(int x,int fa)
{
point=-1;
f[x]=fa;
vis[x]=1;
for(int i=x;i;i=f[i])
{
q[i].push_back(x);
size[i]++;
if(f[i]&&size[i]*100>(size[f[i]]+1)*90)
{
point=f[i];
}
}
if(point!=-1)
{
int len=q[point].size();
for(int i=0;i<len;i++)
{
vis[q[point][i]]=0;
}
num=size[point];
root=0;
getroot(point,0);
if(point==rot)
{
rot=root;
}
partation(root,f[point]);
}
}
void play(int n,int T,int type)
{
for(int i=2;i<=n;i++)
{
id[i]=i;
}
srand(12345678);
random_shuffle(id+2,id+n+1);
col[1]=1;
size[1]=1;
vis[1]=1;
q[1].push_back(1);
mx[0]=1<<30;
if(type==3)
{ random_shuffle(id+2,id+n+1);
l=r=1;
for(int i=2;i<=n;i++)
{
if(col[id[i]])
{
continue;
}
if(col[explore(l,id[i])])
{
while(!col[id[i]])
{
col[now=explore(r,id[i])]=1;
r=now;
}
}
else
{
while(!col[id[i]])
{
col[now=explore(l,id[i])]=1;
l=now;
}
}
swap(l,r);
}
return ;
}
else
{
rot=1;
for(int i=2;i<=n;i++)
{
now=rot;
while(!col[id[i]])
{
int num=explore(now,id[i]);
if(col[num])
{
while(f[num]!=now)
{
num=f[num];
}
now=num;
}
else
{
add(now,num);
add(num,now);
col[num]=1;
insert(num,now);
now=num;
}
}
}
return ;
}
}

[WC2018]即时战略——动态点分治(替罪羊式点分树)的更多相关文章

  1. BZOJ3435[Wc2014]紫荆花之恋——动态点分治(替罪羊式点分树套替罪羊树)

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...

  2. LOJ2341. 「WC2018」即时战略 [动态点分治]

    LOJ 思路 考虑最蠢的暴力:枚举2~n,从1拉一条到他们的链,需要查询\(n^2\)次,显然不能通过. 考虑优化:如果拉的第一个点已经被访问过了,那么类似二分的做法,一次往那个方向多跳几步. 多跳几 ...

  3. uoj 55 紫荆花之恋 动态点分治+替罪羊式重构+treap

    每插入一个点,直接把它当做重心插入原树,当做是动态点分树一样维护 但这样深度会越来越大,所以我们用类似替罪羊的方法 当树失去平衡时,对子树进行一次点分,保证复杂度 #include <cstdi ...

  4. [Codeforces757G]Can Bash Save the Day?——动态点分治(可持久化点分树)

    题目链接: Codeforces757G 题目大意:给出一棵n个点的树及一个1~n的排列pi,边有边权,有q次操作: 1 l r x 求 $\sum\limits_{i=l}^{r}dis(p_{i} ...

  5. 「WC2018即时战略」

    「WC2018即时战略」 题目描述 小 M 在玩一个即时战略 (Real Time Strategy) 游戏.不同于大多数同类游戏,这个游戏的地图是树形的.也就是说,地图可以用一个由 \(n\) 个结 ...

  6. [WC2014]紫荆花之恋(动态点分治+替罪羊思想)

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...

  7. luoguP3920 [WC2014]紫荆花之恋 动态点分治 + 替罪羊树

    意外的好写..... 考虑点分 \(dis(i, j) \leq r_i + r_j\) 对于过分治中心一点\(u\),有 \(dis(i, u) - r_i = dis(j, u) + r_j\) ...

  8. bzoj3435 [Wc2014]紫荆花之恋(动态点分治+替罪羊树)

    传送门(权限) 传送门(非权限) 题解 我终终终终终终于做出来啦!!! 作为一个没有学过替罪羊树的蒟蒻现场学了一下替罪羊树,作为一个平衡树都写数组版本的看着大佬的指针题解无语只能硬去理解然后照着抄了一 ...

  9. WC2018 即时战略

    交互题 一棵树,一开始只有 1 号点是已知的,其他的都是未知的,你可以调用函数 explore(x,y) ,其中 x 必须是已知的,函数会找到 x 到 y 路径上第二个点,并把它标成已知,求最小步数使 ...

随机推荐

  1. JDK命令行(jps、jstat、jinfo、jmap、jhat、jstack、jstatd、hprof)与JConsole

    很多资料在介绍JDK命令行工具时并不是在Java8环境下,因此还在使用过时的永久区系列的参数,给一些读者造成困难. Java8使用Metaspace(元空间)代替永久区,对于64位平台,为了压缩JVM ...

  2. VC++全屏

    Win32类型的全屏代码: 1. 去掉menu ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = s ...

  3. Vue常规后台系统,路由懒加载实现基于菜单数据并解耦

    路由依赖菜单 场景:文件名与路由组件名完全一致(随便大小写均可) 菜单使用一套,路由又存在一套,这样就很不舒服,于是做了如下处理: 尝试不用懒加载发现有难度,使用懒加载就很轻松了 data.js ex ...

  4. 数学基础IV 欧拉函数 Miller Rabin Pollard's rho 欧拉定理 行列式

    找了一些曾经没提到的算法.这应该是数学基础系最后一篇. 曾经的文章: 数学基础I 莫比乌斯反演I 莫比乌斯反演II 数学基础II 生成函数 数学基础III 博弈论 容斥原理(hidden) 线性基(h ...

  5. 牛客练习赛 A题 筱玛的快乐

    链接:https://ac.nowcoder.com/acm/contest/342/A来源:牛客网 筱玛的快乐 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他语 ...

  6. Django 2.0 学习

    Django django是基于MTV结构的WEB框架 Model 数据库操作 Template 模版文件 View 业务处理 在Python中安装django 2.0 1 直接安装 pip inst ...

  7. C#使用ES

    C#如何使用ES Elasticsearch简介 Elasticsearch (ES)是一个基于Apache Lucene(TM)的开源搜索引擎,无论在开源还是专有领域,Lucene可以被认为是迄今为 ...

  8. pip 安装 和 卸载 django

    1. 在dos命令行中输入 pip 如下命令进行安装: 安装最新的版本的 Django 命令如下: pip install django 安装 指定版本的 Django 命令如下: pip insta ...

  9. 多线程系列之九:Worker Thread模式

    一,Worker Thread模式 也叫ThreadPool(线程池模式) 二,示例程序 情景:一个工作车间有多个工人处理请求,客户可以向车间添加请求.请求类:Request定义了请求的信息和处理该请 ...

  10. 【学习总结】GirlsInAI ML-diary day-5-布尔表达式/Bool

    [学习总结]GirlsInAI ML-diary 总 原博github链接-day5 认识布尔表达式 简单来说,bool 就是对错判断. 给个条件,如果满足条件就返回True, 不满足条件就返回Fal ...