UOJ349 WC2018 即时战略
tags:LCT,交互
题意
有一棵树,你不知道它长啥样,一开始只有 1 是已知的
你每次可以传入 u 和 v,其中 u 要已知,你会得到 u 到 v 的路径上的第二个点,这样 u 到 v 的路径上的第二个点也会变为已知的,让你求出这棵树
有两种情况
- 一条链:要求在 \(O(n+\log n)\) 步求出整棵树
- 一棵树:要求在 \(O(n\log n)\) 步求出整棵树
题解
首先 random_shuffle 一遍
对于一条链,维护已知点的左右端点,然后随机一个端点暴力探索,如果询问得到的点 x 已被探索过,说明在另一个端点,不停扩展即可
对于一棵树,考虑将他树链剖分,可以在树链上二分转折点,然后往下走
直接用 LCT 维护就好了,LCT 的话每次把加入的新点 access 一下就可以保证复杂度了,我也不是很明白,感觉就很对
#include"rts.h"
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
const int N=300005;
int n,id[N],vis[N],L[N],R[N],fa[N],ch[N][2];
void upd(int u){L[u]=ch[u][0]?L[ch[u][0]]:u,R[u]=ch[u][1]?R[ch[u][1]]:u;}
int get(int u){return ch[fa[u]][1]==u;}
int isroot(int u){return ch[fa[u]][0]!=u&&ch[fa[u]][1]!=u;}
void rotate(int u){
int p=fa[u],gp=fa[p],x=get(u);
if(!isroot(p))ch[gp][get(p)]=u;fa[u]=gp;
ch[p][x]=ch[u][x^1],fa[ch[u][x^1]]=p;
ch[u][x^1]=p,fa[p]=u;
upd(p),upd(u);
}
void splay(int u){for(;!isroot(u);rotate(u))if(!isroot(fa[u]))rotate(u==fa[u]?fa[u]:u);}
void access(int u){
for(int i=0;u;i=u,u=fa[u])
splay(u),ch[u][1]=i,upd(u);
}
int findroot(int u){while(!isroot(u))u=fa[u];return u;}
void play(int n,int T,int op){
srand(19260817);
::n=n;rep(i,1,n)id[i]=i;L[0]=0x3f3f3f3f,R[0]=-0x3f3f3f3f;
std::random_shuffle(id+2,id+1+n);
vis[1]=1;
if(op==3){
int a[2]={1,1};
rep(i,2,n){
int u=id[i];if(vis[u])continue;
int x=rand()&1,v=explore(a[x],u);
if(vis[v])x^=1,v=explore(a[x],u);
vis[v]=1;while(v!=u)vis[v=explore(v,u)]=1;
a[x]=u;
}
return;
}
rep(i,1,n)L[i]=R[i]=i;
rep(i,2,n){
if(vis[id[i]])continue;
int u=id[i],lst=findroot(1);
while(lst!=u){
int v=explore(lst,u);
if(!vis[v])vis[v]=1,fa[v]=lst,lst=v;else
if(v==R[ch[lst][0]])lst=ch[lst][0];else
if(v==L[ch[lst][1]])lst=ch[lst][1];else
lst=findroot(v);
}
access(lst);
}
}