思路:在给定的序列中一次那周第Ki小的数,求和。这题用线段树很容易就AC我用的是树状数组,中间涉及到一个二分查找的过程,出了太多错误了,这个题WA成狗了。。。(1)二分中求最左的数(2)树状数组的初始化本题很特殊。。。
#include <iostream> #include <string> #include <cstring> #include <cstdio> #include <algorithm> #include <memory> #include <cmath> #include <bitset> #include <queue> #include <vector> #include <stack> using namespace std; const int MAXN = 280000; const int INF = (1<<30); #define CLR(x,y) memset(x,y,sizeof(x)) #define MIN(m,v) (m)<(v)?(m):(v) #define MAX(m,v) (m)>(v)?(m):(v) #define ABS(x) ((x)>0?(x):-(x)) #define rep(i,x,y) for(i=x;i<y;++i) long long tre[MAXN]; int n,t,tt,k; int n_tre; long long ans; int lowbit(int x) { return x&(-x); } void modify(int ind, const int& delta) { for( ; ind <= n_tre; ind +=lowbit(ind)) tre[ind] += delta; } int get_sum(int ind) { int sum = 0; for( ; ind != 0; ind -= lowbit(ind)) sum += tre[ind]; return sum; } int b_search(const int& x) { int mid,l,r; int tmp; l = 1; r = n_tre-1; while( l < r ){ mid = (l+r)>>1; tmp = get_sum(mid); if( tmp >= x ) r = mid; else l = mid + 1; } return l; } int init() { int i; CLR(tre,0); rep(i,1,MAXN) tre[i] = lowbit(i); return 0; } int work() { int i,j,tmp; long long ind,ans; n_tre = MAXN; rep(t,0,tt){ init(); ans = 0; scanf("%d%d",&n,&k); rep(i,0,k){ scanf("%d",&tmp); ind = b_search(tmp); ans += ind; modify(ind,-1); } printf("Case %d: %I64d\n",t+1,ans); } return 0; } int main() { scanf("%d",&tt); work(); }