• [TJOI2011]树的序(贪心,笛卡尔树)


    [TJOI2011]树的序

    题目描述

    众所周知,二叉查找树的形态和键值的插入顺序密切相关。准确的讲:1、空树中加入一个键值k,则变为只有一个结点的二叉查找树,此结点的键值即为k;2、在非空树中插入一个键值k,若k小于其根的键值,则在其左子树中插入k,否则在其右子树中插入k。

    我们将一棵二叉查找树的键值插入序列称为树的生成序列,现给出一个生成序列,求与其生成同样二叉查找树的所有生成序列中字典序最小的那个,其中,字典序关系是指对两个长度同为n的生成序列,先比较第一个插入键值,再比较第二个,依此类推。

    输入输出格式

    输入格式:

    第一行,一个整数,n,表示二叉查找树的结点个数。第二行,有n个正整数,k1到kn,表示生成序列,简单起见,k1~kn为一个1到n的排列。

    输出格式:

    一行,n个正整数,为能够生成同样二叉查找数的所有生成序列中最小的。

    输入输出样例

    输入样例#1: 复制

    4
    1 3 4 2

    输出样例#1: 复制

    1 3 2 4

    说明

    对于20%的数据,n ≤ 10。

    对于50%的数据,n ≤ 100。

    对于100%的数据,n ≤ 100,000。

    题解

    先看出题目是直接建树然后贪心输出中序遍历。
    然后交上去。发现如果树是链的话就被卡成(O(n^2))
    怎么办呢?点开题解
    发现题解多是笛卡尔树。
    笛卡尔树是什么鬼东西(蒟蒻表示不会啊
    那就去学(抄题解)吧。

    笛卡尔树类似于(treap)
    维护两个值,一个为(key)值即点权值,另一个在本题维护为(id),即出现顺序。
    笛卡尔树是利用单调栈的特性建树的。
    按样例的(key)值从小到大排序后。
    (id)值为(1,4,2,3.)
    我们先把(1)放进树。
    然后让(1)点连右儿子(key)值为(2),(id)(4)的点。
    然后(key)值为(3)时,前面的(2)(id)比3的(id)大。
    即按中序遍历,(3)的左儿子是(2)
    于是就断开(1)连向(2)的边,然后连向(3),并让(3)(2)连一条边作为左儿子。
    建树的性质就是这样的。
    (O(n))建树。

    代码

    先上(O(n^2))写法

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int N=1000001;
    struct node{
        int ch[2],vi;
    }t[N<<1];
    int ch[N],n,cnt=1,ans[N],tot;
    int read(){
        int x=0,w=1;char ch=getchar();
        while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*w;
    }
    
    void build(int x){
        int root=1;
    	while(t[root].ch[t[root].vi<ch[x]])root=t[root].ch[t[root].vi<ch[x]];
        t[root].ch[t[root].vi<ch[x]]=++cnt;
        t[cnt].vi=ch[x];
    }
    
    void dfs(int x){
        ans[++tot]=t[x].vi;
        if(t[x].ch[0])dfs(t[x].ch[0]);
        if(t[x].ch[1])dfs(t[x].ch[1]);
    }
    
    int main(){
        n=read();
        for(int i=1;i<=n;i++)ch[i]=read();
        t[1].vi=ch[1];
        for(int i=2;i<=n;i++)build(i);
        dfs(1);
        for(int i=1;i<=n;i++)printf("%d ",ans[i]);
        return 0;
    }
    



    AC代码

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int N=1000010;
    struct node{
    	int vi,ch[2],fa,id;
    }ch[N],t[N];
    int n,tot,line[N];
    int read(){
    	int x=0,w=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*w;
    }
    
    bool cmp(node a,node b){
    	return a.vi<b.vi;
    }
    
    void add(int fa,int now,int f){
    	t[fa].ch[f]=now;
    }
    
    void dfs(int x){
    	if(!x)return;
    	printf("%d ",t[x].vi);
    	dfs(t[x].ch[0]);dfs(t[x].ch[1]);
    }
    
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++){
    		ch[i].vi=read();ch[i].id=i;
    	}
    	sort(ch+1,ch+n+1,cmp);
    	for(int i=1;i<=n;i++){
    		int last=0;
    		while(tot&&t[line[tot]].id>ch[i].id)
    		last=tot--;
    		t[i].id=ch[i].id;t[i].vi=ch[i].vi;
    		add(line[tot],i,1);add(i,line[last],0);
    		line[++tot]=i;
    	}
    	dfs(t[0].ch[1]);
    	return 0;
    }
    
  • 相关阅读:
    java学习疑问
    HTTP method GET is not supported by this URL
    详解ListView分页(带图片)显示用法案例
    MySQL 字段数据类型/长度
    getRequestDispatcher()与sendRedirect()的区别
    Codeforces Round #754 (Div. 2) D,E 题解
    CCPC2019 Harbin Site B.Binary Numbers
    2020 EC Final D. City Brain
    [USACO15JAN]Grass Cownoisseur G
    CF1295F Good Contest
  • 原文地址:https://www.cnblogs.com/hhh1109/p/9626332.html
Copyright © 2020-2023  润新知