SGU 155 Cartesian Tree(线段树)#by zh

来源:互联网 发布:linux 找不到命令 编辑:程序博客网 时间:2024/04/24 23:35
题意很明确就是构造笛卡尔树,但是时间卡的很紧。之前在POJ上做过这道题,但是那次做的题时间很宽松,用上次的解法放到这题上就TLE了,比赛的时候也没想起来更好的解法。其实现在想想还是比较容易想到的,首先按照k值排序,然后在1到n直接找最小的元素作为根节点,然后左边的元素都是左子树,同样的方法递归找左子树的根节点,在找的过程中更新解,最后直接输出就可以了。
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define MAXN 50005int n;struct Node{    int key,value,num;}data[50005];struct Ans{    int v,pos;    Ans(){};    Ans(int a,int b){v=a,pos=b;}    bool operator <(const Ans &temp) const    {        return v<temp.v;    }}num[MAXN<<2];bool operator <(Node a,Node b){    return a.key<b.key;}int ansp[50005],ansl[50005],ansr[50005];void pushup(int rt){    num[rt]=min(num[rt<<1],num[rt<<1|1]);}void build(int l,int r,int rt){    if(l==r)    {        num[rt].v=data[l].value;        num[rt].pos=l;        return;    }    int m=(l+r)>>1;    build(l,m,rt<<1);    build(m+1,r,rt<<1|1);    pushup(rt);}Ans query(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R)        return num[rt];    int m=(l+r)>>1;    Ans res=Ans(100000,0);    if(L<=m)        res=min(res,query(L,R,l,m,rt<<1));    if(R>m)        res=min(res,query(L,R,m+1,r,rt<<1|1));    return res;}int solve(int l,int r){    Ans temp=query(l,r,1,n,1);    int m=temp.pos;    if(l<m)    {        int ls=solve(l,m-1);        ansp[data[ls].num]=data[m].num;        ansl[data[m].num]=data[ls].num;    }    if(r>m)    {        int rs=solve(m+1,r);        ansp[data[rs].num]=data[m].num;        ansr[data[m].num]=data[rs].num;    }    return m;}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%d%d",&data[i].key,&data[i].value);        data[i].num=i;    }    sort(data+1,data+n+1);    data[0].value=-100000;    build(1,n,1);    solve(1,n);    printf("YES\n");    for(int i=1;i<=n;i++)        printf("%d %d %d\n",ansp[i],ansl[i],ansr[i]);}

原创粉丝点击