洛谷 P1377 [TJOI2011]树的序

来源:互联网 发布:手机查看移动网络信号 编辑:程序博客网 时间:2024/06/06 12:41

传送门
其实此题和那个qbxt的bst是一样的,我们可以按照同样的方法(详见这里)来处理,建出来树,然后就可以直接输出先序遍历即可,这就是贪心的思想。
具体贪心原理:首先,一棵树必须先有根,那么就要先输出根,然后因为字典序最小,所以我们每次都要尽可能地输出合法的最小数,那么根据二叉查找树的性质,我们就应该先输出左子树,然后再输出右子树,那不就是先序遍历了?
代码:

#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<cstdlib>#define ll long longusing namespace std;inline int read(){    int x=0;char ch=' ';int f=1;    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();    if(ch=='-')f=-1,ch=getchar();    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();    return x*f;}int n;int mp[100001];int a[100001];int st[17][100001];int Log[100001];int id[100001];inline int query(int l,int r){    int k=Log[r-l+1];    return min(st[k][l],st[k][r-(1<<k)+1]);}void solve(int l,int mid,int r){    if(l>r)return;    if(l==r){        printf("%d ",l);        return;    }    printf("%d ",mid);    int mn1=0,mn2=0;    if(mid>l){        mn1=query(l,mid-1);    }    if(mid<r){        mn2=query(mid+1,r);    }    if(mn1){        solve(l,mp[mn1],mid-1);    }    if(mn2){        solve(mid+1,mp[mn2],r);    }}int main(){    n=read();    Log[0]=-1;    for(int i=1;i<=n;i++){        Log[i]=Log[i>>1]+1;    }    for(int i=1;i<=n;i++){        a[i]=read();        id[a[i]]=i;    }    for(int i=1;i<=n;i++){        st[0][i]=id[i];        mp[id[i]]=i;    }    for(int k=1;k<=16;++k){        for(int i=1;i+(1<<k)-1<=n;++i){            st[k][i]=min(st[k-1][i],st[k-1][i+(1<<(k-1))]);        }    }    int mn=query(1,n);    solve(1,mp[mn],n);    return 0;}