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;
}

  

原文地址:https://www.cnblogs.com/liulangye/p/2601976.html