这题比赛的时候是狐狸大大敲的..先用了list..结果超时了..果断树状数组A之...其实这题当年做过很类似的: POJ2828 插队排队问题..
初始所有点的值都是1..那么初始时每个点k的1~k之和a[k]就是当前数(当然做了取出操作后就不一样了...)...要取出当前第k大时..用二分夹逼找到a[h]=k的h..再将h位更新为-1.并更新树状数组..那么就相当于将>=h的每个点的a[ ] 都-1了...
刚才自己来敲得时候..没注意最后的结果要用64位整型存储...= =..
Program:
#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<queue>
#define ll long long
using namespace std;
int T,t,n,a[500001];
ll ans;
void insert(int k,int d)
{
while (k<=n)
{
a[k]+=d;
k+=(-k)&k;
}
}
int getsum(int k)
{
int t=0;
while (k>0)
{
t+=a[k];
k-=((-k)&k);
}
return t;
}
int find(int k)
{
int l=0,r=n,mid;
while (r-l>1)
{
mid=(r+l)/2;
if (getsum(mid)>=k) r=mid;
else l=mid;
}
return r;
}
int main()
{
int i,k,p,m;
scanf("%d",&T);
for (t=1;t<=T;t++)
{
scanf("%d%d",&n,&k);
memset(a,0,sizeof(a));
for (i=1;i<=n;i++) insert(i,1);
ans=0;
while (k--)
{
scanf("%d",&p);
m=find(p);
ans+=m;
insert(m,-1);
}
printf("Case %d: %I64d\n",t,ans);
}
return 0;
}