poj 2828

     题目意思是每个人来到之后就会直接插入到pos处的位置,问最终整条队伍的顺序。

     刚开始的时候理解错题意,一直wa,等理解正确后才发现这道题考得很巧妙,真正理解了树状数组和线段树的人才可能做得出来。这里是用树状数组来解决的。大家都知道树状数组的c[]所保存的数据有利于快速的求和从而得到某区间的和或者是处于某一点处数据的排名。这里正是利用第二点作为突破口。

      逆序地求出每一个元素的pos在树状数组的结点位置,即为该元素在队列中的最终位置,而从1到该位置处的区间元素总和就等与pos+1(pos不能为0),因此要配合使用结点元素减1的操作。

      讲得可能还是不好,看代码吧:

 

  1. #include<cstdio>
    #include<iostream>
    using namespace std;
  2. const int N=200100;
    int c[N];
    int pos[N],val[N],ans[N];
    int n;
  3. int lowbit(int n)
  4. {

         return n&(-n);

      }

  1. void del(int p)
    {
     while(p<=N)
     {
      c[p]--;
      p+=lowbit(p);
     }
    }
  2. int getK(int k)
    {
     int ans=0,cnt=0;
     for(int i=18;i>=0;i--)
     {
      ans+=(1<<i);
      if(ans>=n || cnt+c[ans]>=k) ans-=(1<<i);
      else cnt+=c[ans];
     }
     return ans+1;
    }
  3. int main()
    {
     
     while(scanf("%d",&n)==1)
     {
      int i;
      for(i=1;i<=n;i++)
      {
       scanf("%d%d",&pos[i],&val[i]);
       c[i]=lowbit(i);
      }
      for(i=n;i;i--)
      {
       int ps=getK(pos[i]+1);
       ans[ps]=val[i];
       del(ps);
      }
      for(i=1;i<=n;i++)
       printf("%d ",ans[i]);
      printf("/n");
     }
     return 0;
    }

  这题也可以用线段树来求解,思想没变,其实这题和poj 2182是一样的:

 

  1. #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int M=400000;
    struct Tree
    {
     int l,r;
     int cnt;
    }T[3*M];
    struct peo
    {
     int num;
     int val;
     bool operator <(const peo a)const{
      return num<a.num;
     }
    }pe[M/2+100];
    int n,N;
  2. void build(int l,int r,int p)
    {
     T[p].l=l;
     T[p].r=r;
     T[p].cnt=r+1-l;
     if(l==r) return ;
     int mid=(l+r)>>1;
     build(l,mid,p<<1);
     build(mid+1,r,p<<1|1);
    }
  3. void del(int c,int p)
    {
     if(T[p].l==T[p].r)
     {
      pe[n].num=T[p].l;
      T[p].cnt=0;
      return ;
     }
     if(c<=T[p<<1].cnt)
      del(c,p<<1);
     else
      del(c-T[p<<1].cnt,p<<1|1);
     T[p].cnt--;
    }
  4. int main()
    {
     while(scanf("%d",&N)==1)
     {
      int i;
      for(i=1;i<=N;i++)
       scanf("%d%d",&pe[i].num,&pe[i].val);
      build(1,N,1);
      for(n=N;n>0;n--)
      {
       del(pe[n].num+1,1);
      }
      sort(pe+1,pe+N+1);
      for(i=1;i<=N;i++)
       printf("%d ",pe[i].val);
      printf("/n");
     }
     return 0;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值