UOJ#349. 【WC2018】即时战略
分析:
- 对于链的数据,我们瞎随就行,肯定能过去。
- 否则我们希望用一种不超过(log)次询问来找到某个点。
- 首先还是要随机这个询问序列。
- 维护点分树,每次询问后一直跳点分树的父亲,用来求出进入了哪棵点分树中子树。
- 直到这个点未被标记,则插入这个点。
- 这里我使用替罪羊式重构的方法维护这棵点分树。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include "rts.h"
using namespace std;
#define N 300050
#define pb push_back
#define ep explore
#define AL 0.75
int n,Q[N],S[N],vis[N],cnt,head[N],to[N<<1],nxt[N<<1];
int used[N],tot;
vector<int>v[N];
int tt[N],rt,fa[N],siz[N],fk[N],root,g[N];
void chain() {
int p=1,q=1,i;
for(i=1;i<=n;i++) tt[i]=i;
random_shuffle(tt+2,tt+n+1);
i=1;
vis[1]=1;
while(1) {
for(;i<=n&&vis[tt[i]];i++) ;
if(i>n) break;
int r=ep(p,tt[i]);
if(vis[r]) {
r=ep(q,tt[i]);
q=r; vis[q]=1;
while(q!=tt[i]) {
int t=ep(q,tt[i]);
vis[t]=1; q=t;
}
}else {
p=r; vis[p]=1;
while(p!=tt[i]) {
int t=ep(p,tt[i]);
vis[t]=1; p=t;
}
}
swap(p,q);
}
}
inline void add(int u,int v) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
void gr(int x,int y) {
int i; g[x]=1; fk[x]=0;
for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) {
gr(to[i],x); g[x]+=g[to[i]];
fk[x]=max(fk[x],g[to[i]]);
}
fk[x]=max(fk[x],tot-g[x]);
if(fk[x]<fk[root]) root=x;
}
void gd(int x,int y,int rt) {
int i;
siz[rt]++; v[rt].push_back(x);
for(i=head[x];i;i=nxt[i]) if(to[i]!=y&&!used[to[i]]) {
gd(to[i],x,rt);
}
}
void solve(int x) {
used[x]=1;
int i,al=tot;
v[x].clear();
siz[x]=0; gd(x,0,x);
for(i=head[x];i;i=nxt[i]) if(!used[to[i]]) {
tot=g[to[i]]; if(tot>g[x]) tot=al-g[x];
root=0; gr(to[i],x); fa[root]=x; solve(root);
}
}
void insert(int x) {
int t,koishi=0,i;
for(t=x;t;t=fa[t]) {
siz[t]++; v[t].push_back(x);
if(fa[t]&&siz[t]>siz[fa[t]]*AL) koishi=fa[t];
}
if(koishi) {
int p=koishi,tmp=fa[p];
int lim=v[p].size();
for(i=0;i<lim;i++) used[v[p][i]]=0;
tot=lim;
root=0;
gr(p,0);
fa[root]=tmp;
if(!tmp) rt=root;
solve(root);
}
}
void play(int _n,int _T,int dataType) {
n=_n;
if(dataType==3) {
chain(); return ;
}
int i;
for(i=1;i<=n;i++) tt[i]=i;
srand(1919810);
random_shuffle(tt+2,tt+n+1);
vis[1]=1; rt=1; siz[1]=1; v[1].push_back(1); fk[0]=1<<30;
for(i=2;i<=n;i++) {
int x=tt[i],p=rt;
while(!vis[x]) {
int q=ep(p,x);
if(vis[q]) {
for(;fa[q]!=p;q=fa[q]);
p=q;
}else {
add(p,q); add(q,p);
fa[q]=p;
vis[q]=1;
insert(q);
p=q;
}
}
}
return ;
}