loj2341. 「WC2018」即時戰略

題面ios

題解:首先發現對於datatype=3的點,容許的詢問次數是\(O(n+log_n)\)級別的。那麼先考慮樹是一條鏈的狀況。考慮當前咱們已經找到了這個鏈的中間一段,咱們稱其左端點爲\(l\),右端點爲\(r\),那麼此時有意義的詢問顯然是\((l/r,x)\)\(x\)是一個未被探索到的點。咱們稱一次詢問「失敗」,當且僅當詢問的結果是一個已知的節點。若是一次詢問(假設是\((l,x)\))成功了,那麼從\(l\)一直往左拓展,咱們就能找到\(l\)\(x\)這條鏈上的全部點。不然\(x\)必定在\(r\)那邊,咱們向右拓展,也能找到一條鏈上的全部點。考慮毒瘤出題人可能會能夠造數據卡你,咱們把\([2,n]\)這個序列random_shuffle一下,這樣,若是當前還有\(m\)個點沒被探索到,一次探索過程指望能找到\(\frac{m}{2}\)個節點,因此只會有logn次探索過程。因爲每次探索過程只有在第一次探索時可能會失敗,因此失敗的指望次數是\(O(logn)\)的,能夠經過。c++

再考慮datatype=1,2的狀況,此時的操做次數限制大概是\(O(nlogn)\)。也就是說,每次須要只用log次詢問就找到一個未被訪問的點。先考慮一個\(O(n^2)\)的暴力作法:每次都從1號節點開始探索。對於datatype=2的狀況,這樣作是正確的,由於這棵有根樹的最大深度是\(O(logn)\)級別的。那麼考慮對於普通狀況,如何將比較深的樹轉化爲一棵比較「均衡」的樹。dom

想到作動態點分治時,點分樹的深度是\(O(logn)\)的,那麼考慮對於已經經過探索獲得的邊,建出它的點分樹。這樣,每次只須要最多\(O(logn)\)次詢問,就能找到至少一個未被訪問的點。ide

可是考慮將新找到的點加入後,點分樹的平衡性可能會被破壞,但咱們又不可能每次都重構點分樹,那麼考慮替罪羊樹的思想,定義一個alpha值,對於每一個分治中心\(u\),若是在點分樹上存在一個兒子的\(siz>siz_u\times alpha\),咱們就重構這個分治中心的點分樹(只修改點分樹上的一個子樹)。那麼咱們每次找到一些新節點並加入點分樹後,跳一下father,找到點分樹上深度最小的須要重構的點\(u\),進行重構便可。測試

固然用lct也能夠維護這個東西。ui

操做次數和時間複雜度都是\(O(nlogn)\)的,至於重構的複雜度證實,能夠搜一下有關替罪羊樹的博客。spa

代碼:(wc的全部測試點都過了,log上死活過不去extra test,無限d造數據人code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#include<cassert>
#include "rts.h"
using namespace std;
#define F(x,y,z) for(int x=y;x<=z;x++)
#define FOR(x,y,z) for(int x=y;x>=z;x--)
#define I void
#define IN int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
typedef double db;
const int INF=1e9+7;
//IN explore(int,int);
map<int,int>mp[303000];
int N,maxi,Son,lim,cano[300300],num,siz[303000],mx[303000],head[303000],v[303000],vis[303000],tot,sz[303000],fa[303000],xu[303000];
int root,rot;
I solve3(int n){
	F(i,2,n)xu[i]=i;sort(xu+2,xu+1+n);int L,R;L=R=1;
	v[1]=1;
	F(cur,2,n){
		if(v[xu[cur]])continue;
		int i=xu[cur],p=explore(L,i),now;
		if(!v[p]){
			now=p;
			while(1){
				v[now]=1;if(now==i)break;
				now=explore(now,i);
			}
			L=i;
		}
		else{
			now=explore(R,i);
			while(1){
				v[now]=1;if(now==i)break;
				now=explore(now,i);
			}
			R=i;
		}
	}
}
struct E{
	int to,nt;
}e[606000];
#define T e[k].to
I add(int x,int y){e[++tot].to=y;e[tot].nt=head[x];head[x]=tot;}
I findroot(int &roo,int x,int fat){
	siz[x]=1;mx[x]=0;
	for(int k=head[x];k!=-1;k=e[k].nt){
		if(vis[T]||T==fat)continue;
		findroot(roo,T,x);
		siz[x]+=siz[T];mx[x]=max(mx[x],siz[T]);
	}
	mx[x]=max(mx[x],N-siz[x]);
	if(mx[x]<maxi)roo=x,maxi=mx[x];
}
I getroot(int &roo,int pos,int sum){
	maxi=INF;N=sum;findroot(roo,pos,0);
}
I D_1(int x,int fat){
	siz[x]=1;
	for(int k=head[x];k!=-1;k=e[k].nt){
		if(T==fat||vis[T])continue;
		D_1(T,x);siz[x]+=siz[T];
	}
}
I divided(int x,int fat){
//	cerr<<"#"<<x<<" "<<fat<<endl;
	fa[x]=fat;mp[x].clear();
	D_1(x,fat);vis[x]=1;sz[x]=siz[x];
	for(int k=head[x];k!=-1;k=e[k].nt){
		if(T==fat||vis[T])continue;
		int rt;getroot(rt,T,siz[T]);
		mp[x][T]=rt;divided(rt,x);
	}
}
I D_2(int x,int fat){
	vis[x]=0;num++;
	for(int k=head[x];k!=-1;k=e[k].nt){
		if(cano[T]){if(T==lim)Son=x;continue;}if(T==fat)continue;
		D_2(T,x);
	}
}
I rebuild(int n){
	int pos=lim=fa[n];while(pos)cano[pos]=1,pos=fa[pos];
//	cerr<<"!"<<n<<endl;
	num=0;D_2(n,0);
	int rt;getroot(rt,n,num);pos=fa[n];while(pos)cano[pos]=0,pos=fa[pos];
	if(n==root){root=rt;divided(root,0);}
	else{
		mp[lim][Son]=rt;assert(rt);divided(rt,lim);
	}
}
IN ck(int x,int y){
	db w=x*0.6;if(w<y*1.0)return 1;
	return 0;
}/**/
void play(int n,int _T,int type){
	/**/if(type==3)return solve3(n),void();
	F(i,2,n)xu[i]=i;random_shuffle(xu+2,xu+n+1);
	C(head,-1);tot=-1;
	root=v[1]=sz[1]=vis[1]=1;
	F(cur,2,n){
		if(v[xu[cur]])continue;
//		cerr<<"@"<<xu[cur]<<endl;
		int i=xu[cur],p=root,d;
		while(1){
//			cerr<<"@";
//			assert(p);
			d=explore(p,i);
			if(!v[d])break;
			p=mp[p][d];
		}
		int cnt=1,_son=d,now=d,sn=0;v[d]=1;add(p,d);add(d,p);
		while(now^i){
//			cerr<<"#";
			d=explore(now,i);cnt++;N++;
			add(now,d);add(d,now);v[d]=1;
			now=d;
		}
		getroot(rot,now,cnt);mp[p][_son]=rot;divided(rot,p);
		while(p^root){
//			cout<<"$";
			sz[p]+=cnt;if(ck(sz[fa[p]]+cnt,sz[p]))sn=fa[p];
			p=fa[p];
		}
		sz[root]+=cnt;
		if(sn)rebuild(sn);
//		F(j,1,n)if(v[j])cerr<<"%"<<j<<" "<<fa[j]<<endl;
	}
}
//g++ grader.cpp rts.cpp -o rts -O2
相關文章
相關標籤/搜索