Data Structure?
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 4654 Accepted Submission(s): 1522
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
题目大意 : 有T组样例,每组样例有N个数和M组操作, 每次操作找到1到N这个区间第k小的数, 找到后再把它删掉, 输出最后查找的数之和
思路 : 权值线段树, 算是很裸第一道题, 初始将1到N每个数的次数都记为1, 然后从rt = 1开始查找,由于要找的是叶子, 所以中间过程相对简单, 如果左孩子的sum数量 > k, 就往左遍历, 否则往右遍历, k变为 k - sum【左】,直到遍历到根节点更新, 每次操作完删除该叶子节点, 注意数据开long long即可
Accepted code
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & (-x))
#define P2(x) ((x) * (x))
typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 4e5 + 100;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }
struct node
{
ll l, r, sum;
}t[MAXN * 4];
ll n, m, T, X;
void build(ll rt, ll l, ll r) {
t[rt].l = l, t[rt].r = r;
t[rt].sum = 1;
if (l == r) return;
ll mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
t[rt].sum = t[ls].sum + t[rs].sum;
}
ll Query(ll rt, ll k) {
if (t[rt].l == t[rt].r) return t[rt].l; // 叶子节点
if (t[ls].sum >= k) return Query(ls, k); // 左边有就往左跑
else return Query(rs, k - t[ls].sum); 否则往右, 更新k
}
void Update(ll rt, ll x) { // 单点更新
if (t[rt].l == t[rt].r && t[rt].l == x) {
t[rt].sum = 0;
return;
}
ll mid = (t[rt].l + t[rt].r) >> 1;
if (mid < x) Update(rs, x);
else Update(ls, x);
t[rt].sum = t[ls].sum + t[rs].sum;
}
int main()
{
cin >> T;
while (T--) {
sc("%lld %lld", &n, &m);
build(1, 1, n);
ll ans = 0;
for (ll i = 0; i < m; i++) {
ll tmp; sc("%lld", &tmp);
ll cnt = Query(1, tmp);
ans += cnt;
Update(1, cnt);
}
cout << "Case " << ++X << ": ";
cout << ans << endl;
}
return 0;
}