【HDU 4217】【经典题 树状数组求前k大】 Data Structure?【n个数1-n,k次操作,每次取出第ki小的数。问所有取出数字之和。】

传送门:HDU 4217 Data Structure?

描述:

Data Structure?

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 3237    Accepted Submission(s): 1041


Problem Description
Data structure is one of the basic skills for Computer Science students, which is a particular way of storing and organizing data in a computer so that it can be used efficiently. Today let me introduce a data-structure-like problem for you.
Original, there are N numbers, namely 1, 2, 3...N. Each round, iSea find out the Ki-th smallest number and take it away, your task is reporting him the total sum of the numbers he has taken away.
 

Input
The first line contains a single integer T, indicating the number of test cases.
Each test case includes two integers N, K, K indicates the round numbers. Then a line with K numbers following, indicating in i (1-based) round, iSea take away the Ki-th smallest away.

Technical Specification
1. 1 <= T <= 128
2. 1 <= K <= N <= 262 144
3. 1 <= Ki <= N - i + 1
 

Output
For each test case, output the case number first, then the sum.
 

Sample Input
  
  
2 3 2 1 1 10 3 3 9 1
 

Sample Output
  
  
Case 1: 3 Case 2: 14
 

Author
iSea@WHU
 

Source
 

Recommend
lcy   |   We have carefully selected several similar problems for you:   4224  4215  4216  4218  4223 
 
题意:

n个数1-n,k次操作,每次取出第ki小的数。问所有取出数字之和。

思路:

树状数组。开始用树状数组更新一下每个位置的值,如果有数字被去掉就-1。然后在查找第ki小的数字的时候,利用树状数组去进行求和,看数字个数为k时是现在的序列中的第几个。

看网上的代码大部分是二分+树状数组复杂度O(klogn*logn)

复杂度:O(klogn)

代码:

#include <stdio.h>  
#include <string.h>  
#include <iostream> 
#define pr(x) cout << #x << "= " << x << "  " ;
#define pl(x) cout << #x << "= " << x << endl;
#define ll __int64
using  namespace  std;

#define mst(ss,b) memset(ss,b,sizeof(ss));
#define For(i,j,n) for(int i=j;i<=n;i++)

template<class T> void read(T&num) {
    char CH; bool F=false;
    for(CH=getchar();CH<'0'||CH>'9';F= CH=='-',CH=getchar());
    for(num=0;CH>='0'&&CH<='9';num=num*10+CH-'0',CH=getchar());
    F && (num=-num);
}
const int N=277777;

int  bit[N],n,k,num;
ll ans;

void update(int i,int x){
  while(i<=n){
    bit[i]+=x;
    i+=i&-i;
  }
}

int query(int k){
  int pos=0,sum=0;
  for(int i=18; i>=0; i--){ //求数字个数为k时是现在的序列中的第几个
    if(pos+(1<<i)<=n && bit[pos+(1<<i)]+sum<k){
      pos+=(1<<i);
      sum+=bit[pos];
    }
  }
  return pos+1;
}

void solve(){
  ans=0;
  mst(bit, 0);
  for(int i=1; i<=n; i++)update(i, 1);
  int kx;
  for(int i=1; i<=k; i++){
    read(kx);
    int s=query(kx);
    ans+=s;
    update(s, -1);
  }
}

int  main(){
  #ifndef ONLINE_JUDGE
  freopen("in.txt","r",stdin);
  #endif

  int t;
  read(t);
  for(int kase=1; kase<=t; kase++){
    read(n);read(k);
    solve();
    printf("Case %d: %I64d\n", kase,ans);
  }
  return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值