zoukankan      html  css  js  c++  java
  • hdu 4302 Holedox Eating 夜

    http://acm.hdu.edu.cn/showproblem.php?pid=4302

    给一个一维的线段L 小动物最初最0点 

    两种操作

    0  x 在x位置添加一个吃的

    1  小动物去吃一个距离它最近的一个吃的 左右距离相等的话选择上一个选择方向

    这个题既可以用线段树 也可以用优先队列

    用优先队列 代码短 好理解 效率高

    但这题确实是一个练习线段树的好题

    线段树代码及其注释:

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<queue>
    #include<cmath>
    #include<stack>
    #include<algorithm>
    
    using namespace std;
    
    const int N=100005;
    struct node
    {
        int l,r;
        int sum;
    }mem[N*3];
    
    int num[N];//记录某个位置的食物数量
    int place,suml,sumr;//小动物的位置 和它左边 右边的食物数量
    int to;//表示方向 1 向右 0 向左
    int ans;//保存答案
    int L,R;//搜索左边和右边最靠近小动物的食物位置
    int Search(int,int );
    void insert(int ,int ,int );
    void Right()//选择右边的食物 进行的一些必要更新
    {
        to=1;
        sumr-=num[R];
        insert(1,R,-num[R]);
        --num[R];
        ans=ans+R-place;
        place=R;
    }
    void Left()//选择左边的食物 进行的一些必要更新
    {
        to=0;
        suml-=num[L];
        insert(1,L,-num[L]);
        --num[L];
        ans=ans+place-L;
        place=L;
    }
    void build(int x,int i,int j)//建树
    {
        mem[x].l=i;
        mem[x].r=j;
        mem[x].sum=0;
        if(i==j)
        return ;
        int mid=(i+j)>>1;
        build(x*2,i,mid);
        build(x*2+1,mid+1,j);
    }
    void insert(int x,int p,int k)//在p这个位置 插入k个食物 k可以为负 用来减少操作
    {
        int mid=(mem[x].l+mem[x].r)>>1;
        if(mem[x].l==mem[x].r)
        {
            mem[x].sum+=k;
            return ;
        }
        if(p<=mid)
        insert(x*2,p,k);
        else
        insert(x*2+1,p,k);
        mem[x].sum=mem[x*2].sum+mem[x*2+1].sum;
    }
    int Search(int x,int d)//搜索第d个食物的位置
    {
        if(mem[x].l==mem[x].r)
        return mem[x].r;
        if(mem[x*2].sum>=d)
        return Search(x*2,d);
        else
        return Search(x*2+1,d-mem[x*2].sum);
    }
    int main()
    {
       int T;
       scanf("%d",&T);
       for(int w=1;w<=T;++w)
       {
           int n,m;
           place=0,suml=0,sumr=0;
           to=1;
           ans=0;
           scanf("%d %d",&n,&m);
           build(1,0,n);
           memset(num,0,sizeof(num));
           while(m--)
           {
               int k,x;
               scanf("%d",&k);
               if(k==0)
               {
                   scanf("%d",&x);
                   ++num[x];
                   if(x!=place)//插入位置 不是在小动物位置才更新线段树
                   insert(1,x,1);
                   if(x<place)
                   ++suml;
                   else if(x>place)
                   ++sumr;
               }else
               {
                   if(num[place]>0)//在小动物位置 直接减少 不需其他操作
                   {
                       --num[place];
                       continue;
                   }
                   if(suml==0&&sumr==0)//没有食物
                   continue;
                   if(sumr==0)//右边没食物 选左边的
                   {
                       L=Search(1,suml);
                       Left();
                   }else
                   if(suml==0)//选右边的
                   {
                       R=Search(1,1);
                       Right();
                   }else
                   if(suml>0&&sumr>0)
                   {
                       L=Search(1,suml);//求的左边最近食物位置
                       R=Search(1,suml+1);//求的右边最近食物位置
                       if(place-L<R-place||(place-L==R-place&&to==0))
                       Left();
                       else
                       Right();
                   }
               }
           }
           printf("Case %d: %d\n",w,ans);
       }
       return 0;
    }
    

    优先队列就比较简单了

    代码:

    include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<queue>
    #include<algorithm>
    
    using namespace std;
    
    const int N=100005;
    priority_queue< int >l;
    priority_queue< int >r;
    int sum[N];
    int main()
    {
       int T;
       scanf("%d",&T);
       for(int w=1;w<=T;++w)
       {
           int n,m;
           scanf("%d %d",&n,&m);
           int place=0;
           int to=1;
           long long ans=0;
           while(!l.empty())
           l.pop();
           while(!r.empty())
           r.pop();
           l.push(-1);
           r.push(-(n+1));
           memset(sum,0,sizeof(sum));
           while(m--)
           {
               int k,x,L,R;
               scanf("%d",&k);
               if(k==0)
               {
                   scanf("%d",&x);
                   ++sum[x];
                   if(x<place)
                   {
                       if(sum[x]==1)
                       l.push(x);
                   }else if(x>place)
                   {
                       if(sum[x]==1)
                       r.push(-x);
                   }
               }else
               {
                   //cout<<place<<" "<<sum[place]<<endl;
                   //cout<<l.top()<<" "<<-r.top()<<endl;
                   if(sum[place]>0)
                   {
                       --sum[place];
                   }else
                   {
                       L=l.top();
                       R=-(r.top());
                       if(L==-1&&R==(n+1))
                       continue;
                       if(L!=-1&&R!=(n+1))
                       {
                           if(place-L<R-place||(place-L==R-place&&to==0))
                           {
                               to=0;
                               ans=ans+place-L;
                               place=L;
                               --sum[L];
                               l.pop();
                           }else
                           {
                               to=1;
                               ans=ans+R-place;
                               place=R;
                               --sum[R];
                               r.pop();
                           }
                       }else
                       {
                           if(L==-1)
                           {
                               to=1;
                               ans=ans+R-place;
                               place=R;
                               --sum[R];
                               r.pop();
                           }else
                           {
                               to=0;
                               ans=ans+place-L;
                               place=L;
                               --sum[L];
                               l.pop();
                           }
                       }
                   }
    
               }
           }
           printf("Case %d: ",w);
           cout<<ans<<endl;
       }
       return 0;
    }
    

      

  • 相关阅读:
    跨浏览器 JavaScript判断窗口是否最小化
    .net 5 获取用户真实IP(nginx)
    C# EF 字符串模糊查询完整实例 lambda
    (zt)过程生成
    (zt)IOS开发常用的开源类库和一些示例
    wp7 生命周期及多任务 详解
    Js中concat()与push()的区别
    Ruby中p、print和puts的区别
    jquery Bug:当表单中包含name为nodeType的input时jquery选择器失效的bug 与您分享我的快乐
    Openlaszlo学习(一)Demo "Applying Constraints"的修改 与您分享我的快乐
  • 原文地址:https://www.cnblogs.com/liulangye/p/2601976.html
Copyright © 2011-2022 走看看