[多校练习] 成都七中数据结构 Challenge 系列解题报告
地址: http://cdqz.openjudge.cn/ds/
Challenge 0
给一个长为 \(n\) 的数列,有 \(M\) 次操作 \((1\le n, m \le 10^5)\),每次操作是以下两种之一:
- 修改数列中的一个数
- 求数列中某位置的值
解答:数组模拟即可。时间复杂度 \(O(n+m)\)。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 5;
int a[maxn], n, m;
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
while(m --) {
char cmd;
cin >> cmd;
if(cmd == 'Q') {
int x;
cin >> x;
cout << a[x] << endl;
} else {
int x, d;
scanf("%d%d", &x, &d);
a[x] = d;
}
}
}
Challenge 1
给一个长为 \(n\) 的数列,有 \(M\) 次操作 \((1\le n, m \le 10^5)\),每次操作是以下两种之一:
- 修改数列中的一个数
- 求数列中某位置在某次操作后的值
解答:我们发现,数据范围是允许带 \(\log\) 的算法的。我们可以对每个位置建立链表,修改时向该位置插入新节点并保存时间,查询时找到第一个时间戳小于 \(k\) 的数字。但是发现动态分配内存且可以二分的指针链表(指针平衡树)十分难写,于是用 vector 代替,同时在时间这个域上二分找第一个时间戳小于 \(k\) 的数字。时间复杂度 \(O(n \log m) 。\)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 1e5 + 5;
struct node {
int tim, val;
} nul;
vector<node> a[maxn];
int b[maxn];
int main() {
int n, m;
nul.tim = 0, nul.val = 0;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) a[i].push_back(nul);
for(int i = 1, x; i <= n; i ++) {
scanf("%d", &x);
node tmp;
tmp.tim = 0, tmp.val = x;
a[i].push_back(tmp);
b[i] ++;
} for(int i = 1; i <= m; i ++) {
char cmd;
cin >> cmd;
if(cmd == 'Q') {
int x, v;
cin >> x >> v;
int l = 1, r = b[x] + 1;
while(l + 1 < r) {
int mid = l + r >> 1;
if(a[x][mid].tim <= v) l = mid;
else r = mid;
} cout << a[x][l].val << endl;
} else {
int x, d;
cin >> x >> d;
node tmp;
tmp.tim = i, tmp.val = d;
a[x].push_back(tmp);
b[x] ++;
}
}
}
未完