1. 程式人生 > >首屆華中區程式設計邀請賽暨第十屆武漢大學程式設計大賽網路預賽C題(HDOJ-4217)

首屆華中區程式設計邀請賽暨第十屆武漢大學程式設計大賽網路預賽C題(HDOJ-4217)

       這題比賽的時候是狐狸大大敲的..先用了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;
}