题目链接:

[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. 二十:让行内元素在div中垂直居中

    (1)使用display:table-cell配合vertical-align:center(淘宝也是这样用的) <div class="method4"> <s ...

  2. HDU - 1166 - 敌兵布阵 线段树的单点修改,区间求和

    #include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> ...

  3. Python_内置函数之max

    源码: def max(*args, key=None): # known special case of max """ max(iterable, *[, defau ...

  4. JavaScript中的各种X,Y,Width,Height

    在JavaScript DOM编程中,会接触很多很多很多关于浏览器的宽高,屏幕的宽高,元素的各种宽高,以及鼠标的坐标等,常常让人搞混.索性就写篇博客整理一下. case 1:鼠标的坐标 获取鼠标的坐标 ...

  5. git [command line] fatal: Authentication failed for

    fatal: Authentication failed for https://www.jianshu.com/p/8a7f257e07b8 git.exe fetch -v --progress ...

  6. yolo buffer is too small for requested array

    yolo.cfg 与 yolo.weights 版本一定要对应, darknet链接 https://github.com/pjreddie/darknet 下载后在cfg文件夹下找到yolov2的配 ...

  7. syncthing 多主机同步文件工具

    周五看了下阮一峰的blog 看到有一个 syncthing的小工具挺好用的 进行了简单的尝试: 1. 下载文件位置: https://syncthing.net 2. 下载文件后的简单安装 绿色版直接 ...

  8. 批量处理word所有回车行

    在WORD中点击CTRL+H,弹出对话框,输入如下替换符

  9. 本地数据访问时出现跨域问题Cross origin requests are only supported for protocol schemes: ……

    从桌面找到Chrome图标,右键属性,快捷方式,起始位置(安装路径) 注:在cmd中访问Program Files文件的方法 %ProgramFiles%=C:\Program Files %Prog ...

  10. Django项目目录介绍

    一个小问题: 什么是根目录:就是没有路径,只有域名..url(r'^$') 补充一张关于wsgiref模块的图片 一.MTV模型 Django的MTV分别代表: Model(模型):和数据库相关的,负 ...