【WC2018】即时战略(动态点分治,替罪羊树)

【WC2018】即时战略(动态点分治,替罪羊树)

题面

UOJ

题解

其实这题我也不知道应该怎么确定他到底用了啥。只是想法很类似就写上了QwQ。
首先链的部分都告诉你要特殊处理那就没有办法只能特殊处理了QWQ。
首先听说有一种均摊\(log\)\(LCT\)做法。
即每次随便\(explore\)一个点,如果这个点未被访问过,直接加入然后继续。
否则在\(LCT\)重链组成的\(Splay\)上跳。
这样子均摊复杂度是\(O(nlogn)\),均摊的询问次数也是\(O(nlogn)\)
然而似乎会被卡。
另一种做法是动态维护点分树。
假装我们有一个点分树,这样子每次询问的时候,如果确定了一个已知节点,那么我们从当前节点向着那个节点的点分树方向移动,这样子可以证明移动次数不会超过一个\(log\)
然而新加入若干点之后点分治的树可能不在平衡,导致复杂度不正确了。
那么类似替罪羊树的思想,如果点分树之间的大小不满足平衡,则拆掉重建。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include "rts.h"
using namespace std;
#define MAX 300300
const double alpha=0.75;
int n,p[MAX],tot;
bool vis[MAX];
namespace Chain
{
	void Solve()
	{
		int L=1,R=1;
		for(int i=1;i<=tot;++i)
		{
			if(vis[p[i]])continue;
			int u=p[i],x=explore(L,u);
			if(vis[x])x=R,R=u;
			else L=u,vis[x]=true;
			while(u!=x)vis[x=explore(x,u)]=true;
		}
	}
}
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int Fa[MAX],size[MAX];
bool del[MAX];
int book[MAX],tim;
void Clear(int u,int ff)
{
	del[u]=false;
	for(int i=h[u];i;i=e[i].next)
		if(e[i].v!=ff&&book[e[i].v]!=tim)
			Clear(e[i].v,u);
}
int Size,mx,rt,root;
void Getroot(int u,int ff)
{
	int ret=0;size[u]=1;
	for(int i=h[u];i;i=e[i].next)
	{
		int v=e[i].v;if(v==ff||book[v]==tim)continue;
		Getroot(v,u);size[u]+=size[v];ret=max(ret,size[v]);
	}
	ret=max(ret,Size-size[u]);
	if(ret<mx)mx=ret,rt=u;
}
void Divide(int u)
{
	book[u]=tim;
	for(int i=h[u];i;i=e[i].next)
	{
		int v=e[i].v;if(book[v]==tim)continue;
		Size=mx=size[v];Getroot(v,u);
		Fa[rt]=u;size[rt]=size[v];Divide(rt);
	}
}
void ReBuild(int u)
{
	++tim;for(int i=Fa[u];i;i=Fa[i])book[i]=tim;
	Clear(u,0);Size=mx=size[u];Getroot(u,0);
	if(u==root)root=rt;
	Fa[rt]=Fa[u];size[rt]=size[u];Divide(rt);
}
void Update(int u)
{
	if(!Fa[u]){if(del[u])ReBuild(u);return;}
	++size[Fa[u]];if(Fa[u]&&alpha*size[Fa[u]]<size[u])del[Fa[u]]=true;
	Update(Fa[u]);if(del[u])ReBuild(u);
}
void Find(int x)
{
	int u=root;
	while(!vis[x])
	{
		int v=explore(u,x);
		if(vis[v]){while(u!=Fa[v])v=Fa[v];u=v;}
		else Add(u,v),Add(v,u),Fa[v]=u,size[v]=1,Update(v),vis[v]=true,u=v;
	}
	
}
void play(int _n,int T,int dataType)
{
	n=_n;vis[1]=true;root=1;size[1]=1;
	for(int i=2;i<=n;++i)p[++tot]=i;
	random_shuffle(&p[1],&p[tot+1]);
	if(dataType==3){Chain::Solve();return;}
	for(int i=1;i<=tot;++i)if(!vis[p[i]])Find(p[i]);
}
posted @ 2019-03-07 20:44  小蒟蒻yyb  阅读(462)  评论(0编辑  收藏  举报