zoukankan      html  css  js  c++  java
  • 洛谷P2713 罗马游戏(左偏树)

    题目

    https://www.luogu.com.cn/problem/P2713

    这题面真的不是十一抽杀吗?

    思路

    没有什么可说的思路,就是一道可并堆的模板题。用左偏树实现是比较简单的一种方式。

    简单介绍一下左偏树。
    一些定义:

    外结点:左子树或右子树为空的结点。

    距离:结点(i)的距离为(i)到它的后代中最近的外结点的边数。

    左偏树满足左偏性质:任意结点的左子结点的距离(geq)右子结点的距离(这个依赖于后面的merge操作来维护),所以,一个结点的距离等于该从该节点开始的最右路径的长度。

    于是,一个(n)个结点的左偏树的距离(leq lfloorlog_2(n+1) floor -1)(抄书上的,不会严格证明,意会就完事了)。

    左偏树的核心操作是合并两棵树(如果往树中添加元素,可以看成是与一棵只有根节点的树合并)。设当前两棵树的根节点分别为x,y,不妨令val(x)(leq)val(y)。

    我们递归下去,始终让y与x的右子树合并(每当遇到val(x)>val(y)的情况时就交换xy),直到有一个值为0。

    语言表达不是很清楚,下面是伪代码:

    Function Merge(A,B)
          If A == NULL Then return B
          If b == NULL Then return A
          if val(A) < val(B)Then swap(A,B)
          right(A)=Merge(right(A),B)
          If dis(right(A)) > dis(left(A)) Then swap(left(A),right(A))
          If right(A) == NULL Then dis(A)=0
          Else dis(A) = dis(right(A))+1
          return A
    End Function
    

    寻找根节点就暴力往上跳就好了。

    对于删除最小值的操作,我们找到根节点,删掉它,合并左右子树(记得先把左右子树的父亲值清零)。

    大概就这些了,对数据结构感兴趣的同学可以看一下这本书高级数据结构——林厚从,接下来是本题代码:

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #define maxn (int)(1e6+10)
    using namespace std;
    int book[maxn];
    struct LTree{
    	int val,fa,lson,rson,len;
    } tree[maxn];
    int getf(int x){
    	if(!tree[x].fa) return x;
    	return getf(tree[x].fa);
    }
    int merge(int x,int y){
    	if(tree[x].val>tree[y].val) swap(x,y);
    	if(!x) return y;
    	if(!y) return x;
    	tree[x].rson=merge(tree[x].rson,y);
    	if(tree[x].lson) tree[tree[x].lson].fa=x;
    	if(tree[x].rson) tree[tree[x].rson].fa=x;
    	if(tree[tree[x].rson].len>tree[tree[x].lson].len) 
    		swap(tree[x].lson,tree[x].rson);
    	if(tree[x].rson) tree[x].len=tree[tree[x].rson].len+1;
    	else tree[x].len=0;
    	return x;
    }
    void MERGE(int x,int y){
    	if(book[x]||book[y]) return;
    	int f1=getf(x),f2=getf(y);
    	if(f1!=f2) merge(f1,f2);
    	return;
    }
    int remove(int x){
    	if(book[x]) return 0;
    	book[x]=1;
    	tree[tree[x].lson].fa=tree[tree[x].rson].fa=0;
    	merge(tree[x].lson,tree[x].rson);
    	return tree[x].val;
    }
    int main(){
    	int n,m,i,x,y;
    	char f[5];
    	scanf("%d",&n);
    	for(i=1;i<=n;++i)
    		scanf("%d",&tree[i].val);
    	scanf("%d",&m);
    	for(i=1;i<=m;++i){
    		scanf("%s",f);
    		if(f[0]=='M'){
    			scanf("%d%d",&x,&y);
    			MERGE(x,y);
    		}
    		if(f[0]=='K'){
    			scanf("%d",&x);
    			printf("%d
    ",remove(getf(x)));
    		}
    	}
    	// system("pause");
    	return 0;
    }
  • 相关阅读:
    Navicat Premium 12 破解汉化64位 windows版本
    Tkinter入门简明教程
    python tkinter-消息框、对话框、文件对话框
    python中ui自动化selenium方法封装分享
    Windows利用EasyWebSvr起web服务
    Windows安装mysql服务端
    北京个人所得税纳税记录打印
    Java并发之ReentrantReadWriteLock源码解析(二)
    Java并发之ReentrantReadWriteLock源码解析(一)
    Java并发之Semaphore源码解析(二)
  • 原文地址:https://www.cnblogs.com/landmine-sweeper/p/13989952.html
Copyright © 2011-2022 走看看