Time Limit: 10000/5000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
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
N
N numbers, namely
1
,
2
,
3...
N
1, 2, 3...N
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
T
T, indicating the number of test cases.
Each test case includes two integers
N
N
N,
K
,
K
K, K
K,K indicates the round numbers. Then a line with
K
K
K numbers following, indicating in
i
i
i (1-based) round, iSea take away the
K
i
Ki
Ki-th smallest away.
Technical Specification
1 <= T <= 128
1 <= K <= N <= 262 144
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
题意:
给定
n
n
n个数字
1
1
1到
n
n
n,将他们存在集合中,有
K
K
K组询问,每次询问一个数字
k
i
ki
ki,将集合中的第
k
i
ki
ki小的数字加到ans上,并将其从集合中删去,问
K
K
K次操作之后,ans为多少。
题解:
权值线段树,每次查询前缀和为
k
i
+
1
ki+1
ki+1的位置,并将其设为0即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
struct seg{
int l,r,w;
}tr[1000004];
int n;
ll ans;
void build(int k,int l,int r){
tr[k].l=l;tr[k].r=r;
if(l==r){
tr[k].w=1;
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
tr[k].w=tr[k<<1].w+tr[k<<1|1].w;
}
int work(int k,int x){
int l=tr[k].l,r=tr[k].r;
if(l==r){
ans+=l;
tr[k].w=0;
return l;
}
int mid=(l+r)>>1;
if(tr[k<<1].w>=x)work(k<<1,x);
else work(k<<1|1,x-tr[k<<1].w);
tr[k].w=tr[k<<1].w+tr[k<<1|1].w;
}
int w33ha(int CASE){
scanf("%d",&n);
build(1,1,n);
ans=0;
int K;scanf("%d",&K);
for(int i=1;i<=K;i++){
int x;scanf("%d",&x);
work(1,x);
}
printf("Case %d: %lld\n",CASE,ans);
return 0;
}
int main(){
int T;scanf("%d",&T);
for(int i=1;i<=T;i++)w33ha(i);
return 0;
}