1. 程式人生 > >LOJ2341. 「WC2018」即時戰略 [動態點分治]

LOJ2341. 「WC2018」即時戰略 [動態點分治]

orm ont ifd () its gist lse long long ifdef

LOJ

思路

考慮最蠢的暴力:枚舉2~n,從1拉一條到他們的鏈,需要查詢\(n^2\)次,顯然不能通過。

考慮優化:如果拉的第一個點已經被訪問過了,那麽類似二分的做法,一次往那個方向多跳幾步。

多跳幾步?那就動態點分治吧。每次最多跳\(\log n\)次就一定可以找到一個點使得它到你現在枚舉的點的路徑全都沒有訪問過,然後一次把這上面的點全都explore一邊即可。

然而,樹的形態你不知道,怎麽動態點分治?

那就動態動態點分治啊2333

類似替罪羊樹的思想,加點時直接連上去,每當某個節點\(u\)下面有一個兒子\(v\)滿足\(size_v>size_u\times \alpha\)時就暴力重構,復雜度就有保證了。

第一次寫還是有點難度的qwq

代碼

吐槽一句:我又用了個vector,然後我又一次進了最慢榜第一頁……

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
    using namespace std;
    #define pii pair<int,int>
    #define fir first
    #define sec second
    #define MP make_pair
    #define rep(i,x,y) for (int i=(x);i<=(y);i++)
    #define drep(i,x,y) for (int i=(x);i>=(y);i--)
    #define go(x) for (int i=head[x];i;i=edge[i].nxt)
    #define templ template<typename T>
    #define sz 303030
    typedef long long ll;
    typedef double db;
    mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
    templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
    templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
    templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
    templ inline void read(T& t)
    {
        t=0;char f=0,ch=getchar();double d=0.1;
        while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
        while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
        if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
        t=(f?-t:t);
    }
    template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
    char __sr[1<<21],__z[20];int __C=-1,__zz=0;
    inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
    inline void print(register int x)
    {
        if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
        while(__z[++__zz]=x%10+48,x/=10);
        while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
    }
    void file()
    {
        #ifdef NTFOrz
        freopen("a.in","r",stdin);
        #endif
    }
    inline void chktime()
    {
        #ifndef ONLINE_JUDGE
        cout<<(clock()-t)/1000.0<<'\n';
        #endif
    }
    #ifdef mod
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
    ll inv(ll x){return ksm(x,mod-2);}
    #else
    ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
    #endif
//  inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std;
#include "rts.h"

int n;
int id[sz];
bool vis[sz]; 

namespace Work1
{
    bool del[sz];
    int size[sz],rt,mn,tot;
    vector<int>V[sz];
    void add(int u,int v){V[u].push_back(v);V[v].push_back(u);}
    void dfs(int x,int fa)
    {
        size[x]=1;int S=0;
        for (int v:V[x]) if (v!=fa&&!del[v])
        {
            dfs(v,x);
            chkmax(S,size[v]);size[x]+=size[v];
        }
        chkmax(S,tot-size[x]);
        if (chkmin(mn,S)) rt=x;
    }
    int getroot(int x,int _tot){tot=_tot;mn=1e9;dfs(x,0);return rt;}
}

namespace Work2
{
    const db alpha=0.7;
    int root=1;
    int fa[sz],size[sz];
    int book[sz],tim;
    void rebuild(int x)
    {
        int sum=size[x]=Work1::tot;Work1::del[x]=1;
        for (int v:Work1::V[x]) if (!Work1::del[v])
        {
            int s=Work1::size[v];if (s>Work1::size[x]) s=sum-Work1::size[x];
            int rt=Work1::getroot(v,s);
            fa[rt]=x;rebuild(rt);
        }
    }
    int dfs(int x,int fa)
    {
        int ret=1;
        Work1::del[x]=0;
        for (int v:Work1::V[x]) 
            if (book[v]!=tim&&v!=fa) 
                ret+=dfs(v,x);
        return ret;
    }
    void check(int x)
    {
        int lst=-1;
        for (int i=x;i!=root;i=fa[i]) if (size[i]>size[fa[i]]*alpha) lst=fa[i];
        if (lst==-1) return;
        ++tim;for (int i=fa[lst];i;i=fa[i]) book[i]=tim;
        int sum=dfs(lst,0);
        int rt=Work1::getroot(lst,sum);fa[rt]=fa[lst];
        rebuild(rt);if (lst==root) root=rt;
    }
    void insert(int x)
    {
        int u=root;
        while (!vis[x])
        {
            int v=explore(u,x);
            if (vis[v]) { while (fa[v]!=u) v=fa[v]; u=v; }
            else
            {
                vis[v]=1,fa[v]=u,Work1::add(u,v),Work1::del[v]=1;
                for (int i=v;i;i=fa[i]) ++size[i];
                check(u=v);
            }
        }
    }
}
    
namespace Line
{
    bool vis[sz];
    void work()
    {
        vis[1]=1;int L=1,R=1;
        rep(i,1,n-1)
        {
            int x=id[i],y;if (vis[x]) continue;
            int p=L,t=0;y=explore(p,x);
            if (vis[y]) p=R,y=explore(p,x),t=1;
            vis[y]=1;p=y;
            while (!vis[x]) y=explore(p,x),vis[y]=1,p=y;
            if (!t) L=p; else R=p;
        }
    }
}

void play(int n,int T,int datatype)
{
    ::n=n;Work2::size[1]=1;Work1::del[1]=1;vis[1]=1;
    rep(i,2,n) id[i-1]=i;
    shuffle(id+1,id+n,rng);
    if (datatype==3) return Line::work();
    rep(i,1,n-1) if (!vis[id[i]]) Work2::insert(id[i]);
    return;
}

LOJ2341. 「WC2018」即時戰略 [動態點分治]