【WC2018】即時戰略(動態點分治,替罪羊樹)
阿新 • • 發佈:2019-03-08
思想 聽說 否則 ++i ostream sin date names shuff 。
然而新加入若幹點之後點分治的樹可能不在平衡,導致復雜度不正確了。
那麽類似替罪羊樹的思想,如果點分樹之間的大小不滿足平衡,則拆掉重建。
【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]); }
【WC2018】即時戰略(動態點分治,替罪羊樹)