[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]即时战略——动态点分治(替罪羊式点分树)的更多相关文章
- BZOJ3435[Wc2014]紫荆花之恋——动态点分治(替罪羊式点分树套替罪羊树)
题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...
- LOJ2341. 「WC2018」即时战略 [动态点分治]
LOJ 思路 考虑最蠢的暴力:枚举2~n,从1拉一条到他们的链,需要查询\(n^2\)次,显然不能通过. 考虑优化:如果拉的第一个点已经被访问过了,那么类似二分的做法,一次往那个方向多跳几步. 多跳几 ...
- uoj 55 紫荆花之恋 动态点分治+替罪羊式重构+treap
每插入一个点,直接把它当做重心插入原树,当做是动态点分树一样维护 但这样深度会越来越大,所以我们用类似替罪羊的方法 当树失去平衡时,对子树进行一次点分,保证复杂度 #include <cstdi ...
- [Codeforces757G]Can Bash Save the Day?——动态点分治(可持久化点分树)
题目链接: Codeforces757G 题目大意:给出一棵n个点的树及一个1~n的排列pi,边有边权,有q次操作: 1 l r x 求 $\sum\limits_{i=l}^{r}dis(p_{i} ...
- 「WC2018即时战略」
「WC2018即时战略」 题目描述 小 M 在玩一个即时战略 (Real Time Strategy) 游戏.不同于大多数同类游戏,这个游戏的地图是树形的.也就是说,地图可以用一个由 \(n\) 个结 ...
- [WC2014]紫荆花之恋(动态点分治+替罪羊思想)
题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...
- luoguP3920 [WC2014]紫荆花之恋 动态点分治 + 替罪羊树
意外的好写..... 考虑点分 \(dis(i, j) \leq r_i + r_j\) 对于过分治中心一点\(u\),有 \(dis(i, u) - r_i = dis(j, u) + r_j\) ...
- bzoj3435 [Wc2014]紫荆花之恋(动态点分治+替罪羊树)
传送门(权限) 传送门(非权限) 题解 我终终终终终终于做出来啦!!! 作为一个没有学过替罪羊树的蒟蒻现场学了一下替罪羊树,作为一个平衡树都写数组版本的看着大佬的指针题解无语只能硬去理解然后照着抄了一 ...
- WC2018 即时战略
交互题 一棵树,一开始只有 1 号点是已知的,其他的都是未知的,你可以调用函数 explore(x,y) ,其中 x 必须是已知的,函数会找到 x 到 y 路径上第二个点,并把它标成已知,求最小步数使 ...
随机推荐
- 史上最全面的Docker容器引擎使用教程
目录 1.Docker安装 1.1 检查 1.2 安装 1.3 镜像加速 1.4 卸载Docker 2.实战Nginx 3.Docker命令小结 4.DockerFile创建镜像 4.1 Docker ...
- 深入浅出Java反射
反射,它就像是一种魔法,引入运行时自省能力,赋予了 Java 语言令人意外的活力,通过运行时操作元数据或对象,Java 可以灵活地操作运行时才能确定的信息 这里笔者就深入浅出总结下Java反射,若有不 ...
- SQLite 实现删除表中前一天的数据
注意点1 要注意SQLite datatime()函数为何获取不到系统本地时间?这个问题,坑死我了. 解决方法详见这篇文章:SQLite datatime()函数为何获取不到系统本地时间? 注意点2: ...
- 百度软件开发实习生c++方向面经(一面)
百度2017实习生软件开发(cpp方向) 首先说一下岗位.分为软件开发,开发测试,前端,机器学习数据挖掘,移动开发,据我观察,报的人数来看,软件开发最多,移动开发和开发测试较少.百度前台还准备了吃的喝 ...
- CSS scroll-behavior属性: 滚动框指定滚动行为
概念 当用户手动导航或者 CSSOM scrolling API 触发滚动操作时,CSS 属性 scroll-behavior 为一个滚动框指定滚动行为,其他任何的滚动,例如那些由于用户行为而产生的滚 ...
- mysql_查的小理解
show create table employee; 对这个语句的小理解: 顿悟呀,之前一直不太理解这条语句,现在忽然觉得明朗起来.他就是展示创建这个表格时的SQL语句.执行上述代码之后结果如下: ...
- #Leetcode# 1009. Complement of Base 10 Integer
https://leetcode.com/problems/complement-of-base-10-integer/ Every non-negative integer N has a bina ...
- MySQL设计SQL语句优化规范
原文:http://bbs.landingbj.com/t-0-240751-1.html 1. 使用mysql explain 对sql执行效率进行检测 ,explain显示了mysql如何使用索引 ...
- IdentityServer4【Introduction】之术语
术语 在规范.文档和对象模型中使用了一些你应该了解的术语. IdentityServer IdentityServer是一个OpenID Connect的提供者,它实现了OpenID Connect和 ...
- C#复习笔记(2)--C#1所搭建的核心基础
通过对C#1所搭建的核心基础的深入了解,可以知道之后的C#版本在C#1的基础上做了很多扩展,而这些扩展都是基于C#搭建的核心基础而来的. 委托 一.编写委托的过程 委托经常和C语言的“函数指针”挂钩. ...