1. 程式人生 > >【WC2018】即時戰略(動態點分治,替罪羊樹)

【WC2018】即時戰略(動態點分治,替罪羊樹)

思想 聽說 否則 ++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】即時戰略(動態點分治,替罪羊樹)