这是一道交互题

题目大意

  有一棵\(n\)个点的树。最开始\(1\)号点是白的,其他点是黑的。

  每次你可以执行一个操作:\(explore(x,y)\)。要求\(x\)是一个白点。该函数会返回从\(x\)到\(y\)的路径上第二个点的坐标并把该点染白。

  要求你把所有点都染成白色。

  设操作次数为\(t\)。

  对于\(30\%\)的数据:这棵树是一条链(不保证\(1\)在链的一端),\(n=300000,t=O(n+\log n)\)

  对于另外\(70\%\)的数据:\(n=300000,t=O(n\log n)\)

题解

  数据范围告诉我们链的情况要分开做。

做法1

  有一个简单的做法:维护当前白色节点的两段,每次加入一个新的节点,如果这个节点是黑的,就先判断这个点在一号点的左边还是右边,在进行扩展。

  可以证明扩展次数是\(2\ln n\)

  记\(E(n)\)为一条长为\(n+1\)的链(有\(n\)个黑色节点),从左边开始扩展的期望次数(最左端是\(1\)号点)。

\[\begin{align}
E(0)&=0\\
E(n)&=1+\frac{1}{n}\sum_{i=0}^{n-1}E(i)\\
n(E(n)-1)&=(n-1)(E(n-1)-1)+E(n-1)\\
nE(n)-n&=nE(n-1)-n+1-E(n-1)+1+E(n-1)\\
nE(n)-nE(n-1)&=1\\
E(n)-E(n-1)&=\frac{1}{n}\\
E(n)&=\sum_{i=1}^n\frac{1}{i}\approx\ln n
\end{align}
\]

  就是枚举\(n\)是第几个扩展的,把前面的离散化到\(1\sim i-1\)。

  因为这题的\(1\)号点不在一端,次数就要乘以\(2\)。

  期望操作次数是\(n+2\ln n\)

  但是这样很大概率拿不了满分。

  我们加入一个新的节点时,可以默认这个点是在\(1\)号点左边,扩展第一次时判断要扩展的点是否是白的。如果是白的就说明新加入的点在\(1\)号点右边。

  当然,加入新节点的第一次扩展要随机扩展左边或右边。

  这样期望扩展次数就是\(\ln n\)了,期望操作次数就是\(n+\ln n\)

做法2

  问题转化为:每次给你一个新的点,要你找出树上离这个点最近的节点。

  • 动态点分治:动态维护点分治树,在点分治树上面跳。

    时间复杂度:\(O(n\log^2 n)\)

    操作次数:\(O(n\log n)\)

  • LCT:每次从根往下在splay上跳,如果调到另一条链上就splay一下继续跳。

    时间复杂度:\(O(n\log n)\)

    操作次数:\(O(n\log n)\)

  这两种做法都可以拿到满分。

  如果你写的是动态点分治,你可能会被卡常。

  UPD:动态点分治跑的很快,LCT没写好会被卡操作常数。

代码

LCT

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<utility>
#include"rts.h"
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
int n;
int b[300010];
int t;
int a[300010][2];
int f[300010];
int l[300010];
int r[300010];
int root(int x)
{
return !f[x]||(a[f[x]][0]!=x&&a[f[x]][1]!=x);
}
void mt(int x)
{
l[x]=r[x]=x;
if(a[x][0])
l[x]=l[a[x][0]];
if(a[x][1])
r[x]=r[a[x][1]];
}
void rotate(int x)
{
int p=f[x];
int q=f[p];
int ps=(x==a[p][1]);
int qs=(p==a[q][1]);
int c=a[x][ps^1];
if(!root(p))
a[q][qs]=x;
a[x][ps^1]=p;
a[p][ps]=c;
if(c)
f[c]=p;
f[p]=x;
f[x]=q;
mt(p);
mt(x);
}
void splay(int x)
{
while(!root(x))
{
int p=f[x];
if(!root(p))
{
int q=f[p];
if((p==a[q][1])==(x==a[p][1]))
rotate(p);
else
rotate(x);
}
rotate(x);
}
}
void access(int x)
{
int y=x,t=0;
while(x)
{
splay(x);
a[x][1]=t;
mt(x);
t=x;
x=f[x];
}
splay(y);
}
void gao(int x)
{
int now=1,v;
splay(now);
while(!b[x])
{
v=explore(now,x);
if(v==r[a[now][0]])
now=a[now][0];
else if(v==l[a[now][1]])
now=a[now][1];
else if(b[v])
{
splay(v);
now=v;
}
else
{
b[v]=1;
f[v]=now;
now=v;
}
}
access(x);
}
void gao1()
{
int i;
for(i=2;i<=n;i++)
if(!b[i])
gao(i);
}
void gao2()
{
int x1=1,x2=1;
int i;
b[1]=1;
for(i=2;i<=n;i++)
{
int x=i;
if(b[x])
continue;
int v=explore(x1,x);
if(!b[v])
{
b[v]=1;
x1=v;
while(x1!=x)
{
v=explore(x1,x);
b[v]=1;
x1=v;
}
}
else
{
while(x2!=x)
{
v=explore(x2,x);
b[v]=1;
x2=v;
}
}
}
}
void play(int _n,int _t,int type)
{
n=_n;
t=_t;
if(type==3)
gao2();
else
gao1();
}

动态点分治

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<utility>
#include<vector>
#include"rts.h"
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
void open(const char *s)
{
#ifndef ONLINE_JUDGE
char str[100];
sprintf(str,"%s.in",s);
freopen(str,"r",stdin);
sprintf(str,"%s.out",s);
freopen(str,"w",stdout);
#endif
}
vector<int> g[300010];
const double alpha=0.8;
int n;
int b[300010];
int t;
int d[300010];
int f[300010];
int s[300010];
int rebuild;
void gao(int now,int x)
{
if(now==x)
return;
int v=explore(now,x);
if(b[v])
{
while(f[v]!=now)
v=f[v];
s[now]-=s[v];
gao(v,x);
s[now]+=s[v];
}
else
{
b[v]=1;
g[now].push_back(v);
g[v].push_back(now);
d[v]=d[now]+1;
s[v]=1;
f[v]=now;
gao(v,x);
s[now]+=s[v];
}
if(s[v]>s[now]*alpha)
rebuild=now;
}
void dfs(int x,int dep)
{
b[x]=0;
for(auto v:g[x])
if(b[v]&&d[v]>=dep)
dfs(v,dep);
}
int ss[300010];
void dfs1(int x,int fa)
{
ss[x]=1;
for(auto v:g[x])
if(v!=fa&&!b[v])
{
dfs1(v,x);
ss[x]+=ss[v];
}
}
int rt,rtsz,num;
void dfs2(int x,int fa)
{
int mx=0;
for(auto v:g[x])
if(!b[v]&&v!=fa)
{
dfs2(v,x);
mx=max(mx,ss[v]);
}
mx=max(mx,num-ss[x]);
if(mx<rtsz)
{
rtsz=mx;
rt=x;
}
}
int build(int x,int dep,int fa,int mi)
{
dfs1(x,0);
num=ss[x];
rtsz=0x7fffffff;
dfs2(x,0);
x=rt;
b[x]=1;
d[x]=dep;
f[x]=fa;
s[x]=1;
for(auto v:g[x])
if(!b[v])
{
int rr=build(v,dep+1,x,mi);
s[x]+=s[rr];
}
return x;
}
int cc[300010];
void gao1()
{
int i;
for(i=1;i<=n;i++)
cc[i]=i;
srand(time(0));
random_shuffle(cc+1,cc+n+1);
b[1]=1;
d[1]=0;
s[1]=1;
f[1]=0;
int r=1;
for(i=1;i<=n;i++)
if(!b[cc[i]])
// if(!b[i])
{
gao(r,cc[i]);
// gao(r,i);
if(rebuild)
{
dfs(rebuild,d[rebuild]);
int rr=build(rebuild,d[rebuild],f[rebuild],d[rebuild]);
if(rebuild==r)
r=rr;
rebuild=0;
}
}
}
void gao3()
{
int x1=1,x2=1;
int i;
b[1]=1;
for(i=1;i<=n;i++)
cc[i]=i;
srand(time(0));
random_shuffle(cc+1,cc+n+1);
for(i=1;i<=n;i++)
{
int x=cc[i];
if(b[x])
continue;
int v=explore(x1,x);
if(!b[v])
{
b[v]=1;
x1=v;
while(x1!=x)
{
v=explore(x1,x);
b[v]=1;
x1=v;
}
}
else
{
while(x2!=x)
{
v=explore(x2,x);
b[v]=1;
x2=v;
}
}
}
}
void gao2()
{
int i,v;
for(i=2;i<=n;i++)
{
int x=1;
while((v=explore(x,i))!=i)
x=v;
}
}
void play(int _n,int _t,int type)
{
n=_n;
t=_t;
if(type==3)
gao3();
else if(type==2)
gao2();
else
gao1();
}

【UOJ349】【WC2018】即时战略 LCT 动态点分治的更多相关文章

  1. 【WC2018】即时战略(动态点分治,替罪羊树)

    [WC2018]即时战略(动态点分治,替罪羊树) 题面 UOJ 题解 其实这题我也不知道应该怎么确定他到底用了啥.只是想法很类似就写上了QwQ. 首先链的部分都告诉你要特殊处理那就没有办法只能特殊处理 ...

  2. uoj#349. 【WC2018】即时战略(动态点分治)

    传送门 头一次看着题解有一种咱不会\(c++\)的感觉-- 看题解吧-- //minamoto #include<bits/stdc++.h> #include "rts.h&q ...

  3. loj2341「WC2018」即时战略(随机化,LCT/动态点分治)

    loj2341「WC2018」即时战略(随机化,LCT/动态点分治) loj Luogu 题解时间 对于 $ datatype = 3 $ 的数据,explore操作次数只有 $ n+log n $ ...

  4. [WC2018]即时战略——动态点分治(替罪羊式点分树)

    题目链接: [WC2018]即时战略 题目大意:给一棵结构未知的树,初始时除1号点其他点都是黑色,1号点是白色,每次你可以询问一条起点为白色终点任意的路径,交互库会自动返回给你这条路径上与起点相邻的节 ...

  5. 「WC2018即时战略」

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

  6. [BZOJ3924][ZJOI2015]幻想乡战略游戏(动态点分治)

    题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打 ...

  7. WC2018 即时战略

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

  8. P3345 [ZJOI2015]幻想乡战略游戏 动态点分治

    \(\color{#0066ff}{ 题目描述 }\) 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越 ...

  9. 【bzoj3924】[Zjoi2015]幻想乡战略游戏 动态点分治

    题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打 ...

随机推荐

  1. vue内置组件 transition 和 keep-alive 使用

    1.transition name - string,用于自动生成 CSS 过渡类名.例如:name: 'fade' 将自动拓展为.fade-enter,.fade-enter-active等.默认类 ...

  2. Sql Server中的nvarchar(n)、varchar(n) 和Mysql中的char(n)、varchar(n)

    刚才有幸看了下 nvarchar(n)和varchar(n),感觉以前的认知有误. nvarchar(n):n指的是字符个数,范围是1-4000,存储的是可变长度的Unicode字符数据. 按字符存储 ...

  3. (第十三周)Final阶段用户调查报告

    项目名:食物链教学工具 组名:奋斗吧兄弟 组长:黄兴 组员:李俞寰.杜桥.栾骄阳.王东涵 用户调查报告 调查时间:2016年12月1日  21:00——2016年12月3日  12:00 项目分享链接 ...

  4. Python容器

    列表 list 1.列表的格式为,把值放入[ ]中 >>> lis = ['a', 1, ['a', 'c', 1]] 2.列表中可以嵌套任何类型 索引 因为列表是有序的,那么我们可 ...

  5. Python之自测代码标识__name__=='__main__'

    __name__是python的默认的自测代码标识,其他文件导入该python文件时,不会执行这行代码以下部分. def yangfan(a): print('yangfan %s' %a) prin ...

  6. linux之常见错误

    在日常开发中,尤其是在Linux中进行操作的时候,经常会碰到各种各样的错误.记录一下,熟能生巧,慢慢参透linux的奥秘 1) 在安装ssl证书的时候,发生certbot命令无法使用的情况 解决方案: ...

  7. react的项目坑

    首先在构造页面时 应该将页面的结构分析好. 在处理数据异步时 将数据结构进行完全的简单结构化. 使用redux时 注意返回的数据是深拷贝还是浅拷贝 否则会产生 数组不为空但是没有值的问题 使用自制数据 ...

  8. golang操作mysql使用总结

    前言 Golang 提供了database/sql包用于对SQL数据库的访问, 作为操作数据库的入口对象sql.DB, 主要为我们提供了两个重要的功能: sql.DB 通过数据库驱动为我们提供管理底层 ...

  9. MySQL5.5 安装配置方法教程

    MySQL下载地址:http://dev.mysql.com/downloads/installer/ 1.首先进入的是安装引导界面 2.然后进入的是类型选择界面,这里有3个类型:Typical(典型 ...

  10. 小程序获取当前页面URL

    var pages = getCurrentPages() //获取加载的页面 var currentPage = pages[pages.length-1] //获取当前页面的对象 var url ...