• [WC2018]即时战略(LCT,splay上二分)


    [UOJ题面]http://uoj.ac/problem/349

    一道非常好的与数据结构有关的交互题。

    首先先看部分分做法,
    一上来我们肯定得钦定一个 (explore) 的顺序,直接随机就好。

    (n) 很小的时候就是直接从 1 号点一路 (explore) 过去就好了,这样次数是 (O(n^2)) 的。

    由于完全二叉树树高是 log 的,所以它实际也能过第二个包。

    然后来看一下链的情况,稍加思考我们可以得到这么一个做法:就是维护当前已经 (explore) 的点的连续区间的左右端点,这样就只需往两边扩展了
    这部分是 (O(n)) 的。能通过第三个包。

    我们把这个想法移到树上,于是就拿一个LCT来维护已经 (explore) 出来的点。

    那么我们的问题就是怎么快速找到一个新点他在哪,然后我们写一个 (Splay) 上二分。
    因为询问得到的是 (now) 的邻点,而当前这颗 (Splay)(now) 的邻点只有前驱和后继,那么只要分三种情况讨论一下下一步去哪里就行:
    (1)前驱(2)后继(3)它属于另一个 (Splay),直接去它那个根就行。
    至于找前驱跟后继的话,可以拿 (Splay) 顺便维护出来。(可以参考Code)

    一些细节:
    为了保证复杂度,每次寻点结束时记得 (Access)
    找根的时候不能 (Splay) 否则过不去 ( ext{Extra Test})

    最后把算法三、四合起来就行。

    #include "rts.h"
    #include "algorithm"
    using namespace std;
    
    const int N=300005;
    int vis[N];
    int p[N];
    
    #define lc(x) (ch[x][0])
    #define rc(x) (ch[x][1])
    
    int ch[N][2],f[N],L[N],R[N];
    
    int g(int x)
    {
    	return rc(f[x])==x;
    }
    
    int nrt(int x)
    {
    	return lc(f[x])==x || rc(f[x])==x;
    }
    
    void up(int x)
    {
    	L[x]=R[x]=x;
    	if(lc(x)) L[x]=L[lc(x)];
    	if(rc(x)) R[x]=R[rc(x)];
    }
    
    void rot(int x)
    {
    	int y=f[x],i=g(x);
    	if(nrt(y))
    		ch[f[y]][g(y)]=x;
    	f[x]=f[y];
    	ch[y][i]=ch[x][i^1];
    	f[ch[x][i^1]]=y;
    	ch[x][i^1]=y;
    	f[y]=x;
    	up(y);
    }
    
    void splay(int x)
    {
    	for(int y=f[x];nrt(x);rot(x),y=f[x])
    		if(nrt(y))
    			rot(g(x)==g(y)?y:x);
    	up(x);
    }
    
    void access(int x)
    {
    	for(int y=0;x;y=x,x=f[x])
    	{
    		splay(x);
    		rc(x)=y;
    	}
    }
    
    int gr(int x)
    {
    	for(;nrt(x);x=f[x]); return x;
    }
    
    void play(int n, int T, int dataType) {
    	vis[1]=1;
    	if(dataType==2)
    	{
    		for(int i=2; i<=n; i++)
    		{
    			if(vis[i])
    				continue;
    			int now=1;
    			while(now!=i) {
    				now=explore(now,i);
    				vis[now]=1;
    			}
    		}
    	}
    	else if(dataType==3)
    	{
    		for(int i=1;i<=n;i++)p[i]=i;
    		int l,r;
    		l=r=1;
    		srand(20030118);
    		for(int i=1;i<=5*n;i++)
    		{
    			int x=rand()%n+1;
    			int y=rand()%n+1;
    			swap(p[x],p[y]);
    		}
    		for(int i,j=1;j<=n;j++)
    		{
    			i=p[j];
    			if(vis[i])
    				continue;
    			int now=explore(l,i);
    			if(!vis[now])
    			{
    				vis[now]=1;
    				while(now!=i) {
    					now=explore(now,i);
    					vis[now]=1;
    				}
    				l=i;
    			}
    			else
    			{
    				now=explore(r,i);
    				vis[now]=1;
    				while(now!=i) {
    					now=explore(now,i);
    					vis[now]=1;
    				}
    				r=i;
    			}
    		}
    	}
    	else
    	{
    		for(int i=1;i<=n;i++)p[i]=i;
    		srand(20030118);
    		for(int i=1;i<=5*n;i++)
    		{
    			int x=rand()%n+1;
    			int y=rand()%n+1;
    			swap(p[x],p[y]);
    		}
    		for(int i,j=1;j<=n;j++)
    		{
    			i=p[j];
    			if(vis[i])
    				continue;
    			int now=gr(1);
    			while(now!=i)
    			{
    				while(1)
    				{
    					int t=explore(now,i);
    					if(t==R[lc(now)]) now=lc(now);
    					else if(t==L[rc(now)]) now=rc(now);
    					else {
    						if(!vis[t])
    							vis[t]=1,f[t]=now;
    						now=gr(t);
    						break;
    					}
    				}
    			}
    			access(now);
    		}
    	}
    }
    
  • 相关阅读:
    Golang学习开篇——Go语言优势
    Ubuntu —— 查看和开放端口
    mysql——sql语句
    python模块——xlwt
    字典容器类型使用之坑
    pandas——将sql查询结果,分几部分存入excel
    pandas 点击 excel 表格数据,跳转到 sheet2
    datetime——计算前一天的这个时间 坑
    报错总结
    nginx——部署前端
  • 原文地址:https://www.cnblogs.com/bestwyj/p/10902869.html
Copyright © 2020-2023  润新知