题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4217
题目大意:给n和k,以及k个数(序列ki),表示一个1到n的序列,进行k次操作,每次取出序列中第ki小的数,问经过k次操作后,取出的数的和为多少?
线段树,segTree维护的是rt节点下区间里有多少个数,每次删除时把包含第ki小的数的区间大小都减1。
结果用long long.
#include <iostream>
#include <cstdio>
#include <fstream>
#include <string>
#include <deque>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 270000;
int segTree[maxn<<2];
void build(int node, int l, int r) {
if(l == r) {
segTree[node] = 1;
return ;
}
int mid = (l + r) >> 1;
build(2 * node, l, mid);
build(2 * node + 1, mid + 1, r);
// segTree[node] = r - l + 1;
segTree[node] = segTree[node<<1] + segTree[node<<1|1];
}
int del(int node, int l, int r, int x) {
segTree[node] --;
if(l == r) {
return l;
}
int mid = (l + r) >> 1;
if(x <= segTree[node<<1]) {
return del(2*node, l, mid, x);
}
else {
return del(2*node+1, mid + 1, r, x-segTree[node<<1]);
}
}
int main() {
int t, cas = 1;
int n, k, x;
scanf("%d", &t);
long long sum = 0;
while (t --) {
scanf("%d%d", &n, &k);
build(1, 1, n);
sum = 0;
for(int i = 0; i < k; i ++) {
scanf("%d", &x);
sum += (long long)del(1, 1, n, x);
}
printf("Case %d: %I64d\n", cas ++, sum);
}
return 0;
}