#HDU 4217 Data Structure? (权值线段树)

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;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值