[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 路径上第二个点,并把它标成已知,求最小步数使 ...
随机推荐
- .NET Core 2.1中的分层编译(预览)
如果您是.NET性能的粉丝,最近有很多好消息,例如.NET Core 2.1中的性能改进和宣布.NET Core 2.1,但我们还有更多的好消息.分层编译是一项重要的新特性功能,我们可以作为预览供任何 ...
- BOM基础 计时器 定时器 DOM 基础
-------------------------------------------滴水穿石,我心永恒. day48 CSSJS 1 ECMA script 2 BOM browser object ...
- 我的微信小程序第二篇
在上一篇<我的微信小程序第一篇(入门)>中,很多人问我什么是微信小程序,在这里我要说一下这个是我的失误啦,我默认大家都知道微信小程序,其实可能行内人士都知道小程序,好多非行内朋友可能平时不 ...
- Hadoop生态的配置
网盘下载地址 链接: https://pan.baidu.com/s/19qWnP6LQ-cHVrvT0o1jTMg 密码: 44hs Hadoop伪分布式配置 Hadoop 可以在单节点上以伪分布 ...
- python实现满二叉树递归循环
一.二叉树介绍点这片文章 二叉树及题目介绍 例题: 有一颗满二叉树,每个节点是一个开关,初始全是关闭的,小球从顶点落下, 小球每次经过开关就会把它的状态置反,这个开关为关时,小球左跑,为开时右跑.现在 ...
- Telnet服务器和客户端请求处理
Telnet服务器和客户端请求处理 本文的控制台项目是根据SuperSocket官方Telnet示例代码进行调试的,官方示例代码:Telnet示例. 开始我的第一个Telnet控制台项目之旅: 创建控 ...
- elasticsearch5.0版本的head安装
elasticsearch5.0版本的head安装 elasticsearch5.0版本由于刚出不久,并且与2.0版本的差距较大.所以,目前大家对5.0的一些使用还有所陌生.这里先把关于head插件的 ...
- HTTPS的SSL证书配置
SSL证书 TOMCAT7.0部署_百度经验https://jingyan.baidu.com/article/7082dc1c65066be40a89bda8.html SSL证书安装指引 - 青春 ...
- centos yum install oracle java
How to install Java on CentOS 7 | Linuxizehttps://linuxize.com/post/install-java-on-centos-7/ CentOS ...
- asp.net mvc5 action多个参数
需要完成http://site.com/user/add/1/2这样的url解析 使用action的参数直接获取数据的方式 Action声明如下 ) { ViewBag.clubID = id; ) ...