Atcoder Beginner Contest 306E


Atcoder Beginner Contest 306E

题目描述

長さ $ N $ の数列 $ A=(A_1,A_2,\dots,A_N) $ があり、最初全ての項が $ 0 $ です。
入力で与えられる整数 $ K $ を用いて関数 $ f(A) $ を以下のように定義します。

  • $ A $ を降順に (広義単調減少となるように) ソートしたものを $ B $ とする。
  • このとき、 $ f(A)=B_1\ +\ B_2\ +\ \dots\ +\ B_K $ とする。

この数列に合計 $ Q $ 回の更新を行うことを考えます。
数列 $ A $ に対し以下の更新を $ i=1,2,\dots,Q $ の順に行い、各更新ごとにその時点での $ f(A) $ の値を出力してください。

  • $ A_{X_i} $ を $ Y_i $ に変更する。

输入格式

入力は以下の形式で標準入力から与えられる。

$ N $ $ K $ $ Q $ $ X_1 $ $ Y_1 $ $ X_2 $ $ Y_2 $ $ \vdots $ $ X_Q $ $ Y_Q $

输出格式

全体で $ Q $ 行出力せよ。そのうち $ i $ 行目には $ i $ 回目の更新を終えた時点での $ f(A) $ の値を整数として出力せよ。

输入输出样例 #1

输入 #1

1
2
3
4
5
6
7
8
9
10
11
4 2 10
1 5
2 1
3 3
4 2
2 10
1 0
4 0
3 1
2 0
3 0

输出 #1

1
2
3
4
5
6
7
8
9
10
5
6
8
8
15
13
13
11
1
0

说明/提示

制約

  • 入力は全て整数
  • $ 1\ \le\ K\ \le\ N\ \le\ 5\ \times\ 10^5 $
  • $ 1\ \le\ Q\ \le\ 5\ \times\ 10^5 $
  • $ 1\ \le\ X_i\ \le\ N $
  • $ 0\ \le\ Y_i\ \le\ 10^9 $

Sample Explanation 1

この入力では $ N=4,K=2 $ です。 $ Q=10 $ 回の更新を行います。 - $ 1 $ 回目の更新を受けて $ A=(5,0,0,0) $ となります。このとき $ f(A)=5 $ です。 - $ 2 $ 回目の更新を受けて $ A=(5,1,0,0) $ となります。このとき $ f(A)=6 $ です。 - $ 3 $ 回目の更新を受けて $ A=(5,1,3,0) $ となります。このとき $ f(A)=8 $ です。 - $ 4 $ 回目の更新を受けて $ A=(5,1,3,2) $ となります。このとき $ f(A)=8 $ です。 - $ 5 $ 回目の更新を受けて $ A=(5,10,3,2) $ となります。このとき $ f(A)=15 $ です。 - $ 6 $ 回目の更新を受けて $ A=(0,10,3,2) $ となります。このとき $ f(A)=13 $ です。 - $ 7 $ 回目の更新を受けて $ A=(0,10,3,0) $ となります。このとき $ f(A)=13 $ です。 - $ 8 $ 回目の更新を受けて $ A=(0,10,1,0) $ となります。このとき $ f(A)=11 $ です。 - $ 9 $ 回目の更新を受けて $ A=(0,0,1,0) $ となります。このとき $ f(A)=1 $ です。 - $ 10 $ 回目の更新を受けて $ A=(0,0,0,0) $ となります。このとき $ f(A)=0 $ です。

算法

STL 模拟

吐槽

这题写的极为复杂,花费了大概2小时的时间调整细节,赛时绝对寄了

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<"\n"
#define EPS 1e-8
#define IOS ios::sync_with_stdio(0),cin.tie(0)
#define all(v) v.begin(),v.end()
using namespace std;
using i64 = long long;
using ull = unsigned long long;
using pi = pair<int,int>;
using pl = pair<long long,long long>;
static constexpr int ALPHABET_SIZE = 26;
static constexpr i64 N = 1000000 + 5;
static constexpr int MOD = 998244353;
void solve() {
//有q个查询, 每次询问将数列中的axi -> yi(1 - based), 求前k个数的和
//一个set维护备选数组, 一个set维护已选数组(size <= k)
//每次操作先判断是否赋值, 然后然后判断是否大于已选set里最小的数
//同时维护sum
//额外维护state和nums, 代表每个索引的状态和数值, 0: 未赋值, 1: 在已选数组, 2: 在备选数组
//当一个索引已经赋值,则删掉对应数组里的元素,重新插入
int n, k, q;
cin >> n >> k >> q;
i64 sum = 0;
vector<int> states(n + 1);
vector<i64> nums(n + 1);
set<pl> chosen, candidate;
//每次都要更新state, nums
while (q--) {
i64 idx, newNum;
cin >> idx >> newNum;
if (chosen.size() < k) {
int state = states[idx];
if (state == 0) {
states[idx] = 1;
nums[idx] = newNum;
sum += newNum;
chosen.insert({newNum, idx});
} else {
//state只能为1
i64 oldNum = nums[idx];
nums[idx] = newNum;
sum -= oldNum;
sum += newNum;
chosen.erase({oldNum, idx});
chosen.insert({newNum, idx});
}
} else {
int state = states[idx];
if (state == 0) {
nums[idx] = newNum;
pl minChosen = *chosen.begin();
if (newNum > minChosen.first) {
states[idx] = 1;
states[minChosen.second] = 2;
sum -= minChosen.first;
sum += newNum;
//minChosen调整位置
chosen.erase(minChosen);
candidate.insert(minChosen);
chosen.insert({newNum, idx});
} else {
states[idx] = 2;
candidate.insert({newNum, idx});
}
}
else if (state == 1) {
//防止==k的情况出现re
i64 oldNum = nums[idx];
sum -= oldNum;
nums[idx] = newNum;
chosen.erase({oldNum, idx});
if (candidate.size()) {
pl maxCandidate = *candidate.rbegin();
if (newNum >= maxCandidate.first) {
sum += newNum;
chosen.insert({newNum, idx});
} else {
states[idx] = 2;
states[maxCandidate.second] = 1;
sum += maxCandidate.first;
candidate.erase(maxCandidate);
candidate.insert({newNum, idx});
chosen.insert(maxCandidate);
}
} else {
sum += newNum;
chosen.insert({newNum, idx});
}
}
else {
i64 oldNum = nums[idx];
nums[idx] = newNum;
candidate.erase({oldNum, idx});
pl minChosen = *chosen.begin();
if (newNum > minChosen.first) {
states[idx] = 1;
states[minChosen.second] = 2;
sum -= minChosen.first;
sum += newNum;
//minChosen调整位置
chosen.erase(minChosen);
candidate.insert(minChosen);
chosen.insert({newNum, idx});
} else {
candidate.insert({newNum, idx});
}
}
}
cout << sum << "\n";
}
}
int main()
{
IOS;
int t = 1;
// cin >> t;
while(t--) {
solve();
}
return 0;
}



  目录