• 【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]);
    }
    
  • 相关阅读:
    【代码笔记】JTable 、TableModel的使用3
    学习JSP(二)
    Tomcat文件配置
    学习JSP(一)
    配置elipse
    配置Jdk
    定义新运算练习题
    学习JAVA所需的东西
    学习秘籍
    总有那么一个人
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10492193.html
Copyright © 2020-2023  润新知