【[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]);
    }
}
 
posted @ 2018-12-24 19:26  Newuser233  阅读(10)  评论(0)    收藏  举报