【[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]); } }