[STL]hdu5233

题意:
给出一组数据n个数,m个询问q,问最近的q的输入下标是多少?

分析:
首先数据量比较大100000,查询的话肯定要用些技巧,刚开始想的是二分查询,用set,可是不知道set里放数据结构struct如何按照关键字lower_bound()。后来看了官方题解,先把数据离散话,然后利用set[]来存储下标。那么输出的时候就直接输出begin,删除也可以erase().
这里有个trick,刚开始用的vector q[],然后T。。。后来换set就A了,原来vector<>的push_back()是O(n)的,set的inset是O(logn).

这里简单查一下vector push_back的知识,当每次push_back的时候vector法先空间不够的时候就会copy元素,然后扩大空间,vector 的 push_back 在发现空间不足时自动将空间以 2 的指数增长:0 -> 1 -> 2 -> 4 -> 8 -> 16 -> 32 …

引用:
http://blog.csdn.net/tyzhaoqi2004/article/details/6882660

vector管理内存的方式是内存不够用时,就分配capacity大小的内存,每次重新分配内存,都要copy之前放入的元素,capacity为已经分配的内存。

例如:push_back n个int元素,n为2的幂次加1

元素序号 copy元素 capacity

1 1 1

2 2 2

3 3 4

4 1 4

5 5 8

.。。。

n n 2n

归纳得到copy元素次数字和为

1+2+4+8.。。+(n-1)/2+(n-1)+n

前面部分为一个等比数列,求和为(n-1)/2,最后数列求和为3n-1/3,时间复杂度为O(n)。

所以在不指定reverse的时候,vector push_back n个元素的时间复杂度为O(n)。

对于set:
set::find和set::insert消耗时间级别都为logN.


可是试了一下预先分配vector的空间大小,还是T。。。

好吧,来看一下vector的erase函数

    template<typename _Tp,_Alloc>typename vector<_Tp,_Alloc>::iterator  
    vector<_Tp,_Alloc>::erase(iterator __postion) {  
        if (__postion + 1 != end())  
            std::copy(__postion + 1, end(), __postion);  
        --this->_M_impl._M_finish;  
        this->_M_impl.destroy(this->_M_impl._M_finish);  
        return __postion;  
    }  

它是O(n)是把删除数据后面的数据copy到前面。copy是把删除元素位置后面元素向前移位, 然后 –finish把end位向前移动, 这2句都好理解保持内存连续把删除的空位补上同时把队尾往前挪。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <algorithm>
#define read freopen("q.in","r",stdin)
#define LL long long
#define maxn 100005
using namespace std;
set<int>  mp[maxn];
map<int,int> c;
//http://www.2cto.com/kf/201108/100912.html
//http://blog.csdn.net/tyzhaoqi2004/article/details/6882660
int main()
{
    //read;
   int n,m;
   while(scanf("%d%d",&n,&m)!=EOF)
   {
       int i,j,q,x,t=0;
       for(i=1;i<=n;i++)
        mp[i].clear();
        c.clear();
       for(i=0;i<n;i++)
       {
          scanf("%d",&x);
          if(!c[x])c[x]=++t;
          mp[c[x]].insert(i+1);

         // cout<<c[x]<<" ";
       }
       //for(i=1;i<=t;i++)cout<<c[i]<<" ";
    //   cout<<endl;
       for(i=0;i<m;i++)
       {
          scanf("%d",&q);
          if(mp[c[q]].size()==0)
          {
             printf("-1\n");
          }
          else
          {
            //  cout<<mp[q].size()<<" %% "<<endl;
             printf("%d\n",*(mp[c[q]].begin()));
             mp[c[q]].erase(mp[c[q]].begin());
            // cout<<mp[q].size()<<" %% "<<endl;
          }
       }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值