• poj 3666 Making the Grade 夜


    http://poj.org/problem?id=3666

    这是一道 练习左偏树的好题 不过很多人都是用动态规划做的

    没看过左偏树的建议看看 课件之类的 不难理解 有一份ppt 上有原题 

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<string>
    #include<vector>
    #include<set>
    #include<queue>
    #include<stack>
    #include<cmath>
    #define LL long long
    
    using namespace std;
    
    const int N=2005;
    struct node
    {
        int k,d;
        struct node *l,*r;
    };
    struct node *head[N];//每个左偏树的根节点  大顶堆
    int I;
    int l[N],r[N];//每个左偏树的左右范围 不过我们这里只是保存了中位数(如果有n个元素 中位数我们这里定义为第 n/2个数) 和小于中位数的数
    int a[N];
    void  Left_tree_Merge(struct node *t1,struct node *t2)//将 t2指向的树合并到 t1
    {
        struct node *t=t1->r;
        t1->r=t2;
        if(t==NULL)
        return;
        struct node *w=t1;
        while(w->r!=NULL&&w->r->k>t->k)//找到需要插入的地方 为 w的右孩子
        w=w->r;
        if(w->r==NULL)
        {w->r=t;}//为空直接插入
        else//否则递归合并
        {
            struct node *temp=w->r;
            w->r=t;
            Left_tree_Merge(t,temp);
        }
        return ;
    }
    struct node * Left_tree_pop(struct node *t)//弹出堆顶元素 
    {
        if(t->l==NULL&&t->r!=NULL)
        {return t->r;}
        if(t->l!=NULL&&t->r==NULL)
        {return t->l;}
        if(t->l->k<t->r->k)
        swap(t->l,t->r);
        Left_tree_Merge(t->l,t->r);
        return t->l;
    }
    int update(struct node *t)//更新节点的 距离 维护左偏性
    {
       if(t==NULL)
       return -1;
       int l1=update(t->l);
       int l2=update(t->r);
       t->d=min(l1,l2)+1;
       if(l1<l2)
       swap(t->l,t->r);
       return t->d;
    }
    int solve(int n)
    {
        int I=0;
        for(int i=0;i<n;++i,++I)
        {
            head[I]=new node;
            head[I]->d=0;
            head[I]->l=head[I]->r=NULL;
            head[I]->k=a[i];
            l[I]=r[I]=i;
            while(I>0&&head[I-1]->k>=head[I]->k)//如果需要合并
            {
                Left_tree_Merge(head[I-1],head[I]);
                update(head[I-1]);//合并后更新
                if((r[I]-l[I]+1)%2==1&&(r[I-1]-l[I-1]+1)%2==1)//如果合并后元素过多 减少出一个 然后更新
                {
                    head[I-1]=Left_tree_pop(head[I-1]);
                    update(head[I-1]);
                }
                r[I-1]=r[I];//合并区间
                --I;
            }
        }
        int ans=0;
        for(int i=0;i<I;++i)
        {
            for(int j=l[i];j<=r[i];++j)
            {
                ans+=(abs(head[i]->k-a[j]));//累加
            }
        }
        return ans;
    }
    int main()
    {
        //freopen("data.txt","r",stdin);
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            for(int i=0;i<n;++i)
            scanf("%d",&a[i]);//先求非递减的解
            int ans=solve(n);
            for(int i=0;i<n/2;++i)
            {
                swap(a[i],a[n-i-1]);//将数组逆序后 再求一边便是 非递加的了
            }
            ans=min(ans,solve(n));
            printf("%d\n",ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    Atitit 图像处理30大经典算法attilax总结
    Atitit 图像清晰度 模糊度 检测 识别 评价算法 源码实现attilax总结
    Atitit  rgb yuv  hsv HSL 模式和 HSV(HSB) 图像色彩空间的区别
    Atitit  从 RGB 到 HSL 或 HSV 的转换
    Atitit 图像清晰度 模糊度 检测 识别 评价算法 原理
    Atitit 修改密码的功能流程设计 attilax总结
    atitit 点播系统 概览 v2 qb1.docx
    Atitit dsl exer v3 qb3 新特性
    atitit.TokenService v3 qb1  token服务模块的设计 新特性.docx
    Atitit 异常机制与异常处理的原理与概论
  • 原文地址:https://www.cnblogs.com/liulangye/p/2647867.html
Copyright © 2020-2023  润新知