【[WC2018]即时战略 】交互题+动态点分治重构
最近做了几道交互题,感觉和平时传统题的考虑方向差别还是挺大的。
LOJ2341
题目有点多,有点长,这里看格式挺乱的就不放了。
大意:一棵树,你去交互,调用 explore(x,y) (x为已知节点),那么返回x的儿子中离y最近的那个,并且将那个点变为已知。给定一种explore方案使得最后可以把所有点变为已知。
先把一个序列random_shuffle一下,表示接下来的explore顺序。(防止被毒瘤数据卡掉)
对于链,已经走到的左右端点,肯定一个点不是在左边就是在右边,如果发现访问点已知,就一直走另一端就可以了。
对于一般的情况,一个n^2的想法就是一直顺着explore的回答走到底。
可以想到,其实就是在已知的树里面,explore得到那个点在哪个子树里面,然后递归到那个子树里面去搞。根据我们紫荆花之恋的经验,我们可以动态维护一棵点分树。这样explore的次数就是nlogn的了。
然而我的lj程序只能在loj上跑过,uoj上过不去orz
code:
#include "rts.h"
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<unordered_map>
#include<map>
#include<vector>
using namespace std;
const int maxn = 300005;
int N;
int ps[maxn];
bool vis[maxn];
namespace lian{
int orz[2];
void lian() {
orz[0]=orz[1]=1;
int now = 1;
for(int i=2;i<=N;i++) {
int x = ps[i];
while(!vis[x]) {
int vivi = explore(orz[now],x);
if(vis[vivi]) vivi = explore(orz[now^=1],x);
vis[vivi] = 1; orz[now] = vivi;
}
}
}
}
int en[maxn*2],la[maxn*2],nt[maxn*2],owo;
void adg(int x,int y) {
en[++owo]=y; nt[owo]=la[x]; la[x]=owo;
}
unordered_map<int,int>sont[maxn];//sont[x][y]表示x点分儿子y对应的原树儿子
unordered_map<int,int>mat[maxn];//mat[x][y]表示x原树儿子y的点分儿子
int RT;
int sm,sz[maxn],rtsz,rt,fa[maxn];
int vtim[maxn],tim,vti[maxn];
void gsz(int x,int ba) {
sz[x] = 1;
for(int it=la[x];it;it=nt[it]) {
int y = en[it];
if(vtim[y]!=tim||vti[y]==tim||y==ba) continue;
gsz(y,x);
sz[x] += sz[y];
}
}
void grt(int x,int ba) {
int sso = sm-sz[x];
for(int it=la[x];it;it=nt[it]) {
int y = en[it];
if(vtim[y]!=tim||vti[y]==tim||y==ba) continue;
grt(y,x);
sso = max(sso,sz[y]);
}
if(sso<rtsz) rtsz=sso,rt=x;
}
int siz[maxn];
void delall(int x) {
vtim[x] = tim;
for(auto p:sont[x]) {
delall(p.first);
}
sont[x].clear(); //mat[x].clear();
}
void DC(int x) {
siz[x] = 1;
vti[x] = tim;
for(int it=la[x];it;it=nt[it]) {
int y = en[it];
if(vtim[y]!=tim||vti[y]==tim) continue;
gsz(y,x); sm = sz[y]; rtsz=0x3f3f3f3f; grt(y,x);
int p = rt; fa[p] = x;
sont[x][p] = y;
mat[x][y] = p;
DC(p);
siz[x] += siz[p];
}
}
void rebuild(int x) {
++tim;
delall(x);
gsz(x,0); sm = sz[x]; rtsz = 0x3f3f3f3f;
grt(x,0); int p = rt;
fa[p] = fa[x];
if(RT==x) RT = p;
else {
int kk = sont[fa[x]][x];
sont[fa[x]].erase(x);
mat[fa[x]][kk] = p;
sont[fa[x]][p] = kk;
}
DC(p);
}
int cq = 0;
void update(int x) {
siz[x] = 1;
int cg = 0;
for(int p = x;fa[p];p=fa[p]) {
siz[fa[p]]++;
if(siz[p]*5>siz[fa[p]]*4) cg = p;
}
if(!cg) return;
rebuild(fa[cg]);
cq = 1;
}
void insert(int x) {
int p = RT; cq = 0;
for(;!vis[x];) {
int y = explore(p,x);
if(!vis[y]) {
vis[y] = 1; fa[y] = p;
mat[p][y]=y; sont[p][y]=y;
adg(p,y); adg(y,p);
update(y);
if(cq) break;
}
p = mat[p][y];
}
if(!vis[x]) insert(x);
}
void play(int n,int t,int dateType) {
for(int i=1;i<=n;i++) ps[i] = i;
vis[1] = 1; siz[1] = 1;
RT = 1; srand(19260817);
N = n;
random_shuffle(ps+2,ps+1+n);
if(dateType==3) { lian::lian(); return; }
for(int i=2;i<=n;i++)
{
if(!vis[ps[i]]) insert(ps[i]);
}
}

浙公网安备 33010602011771号