去年新星赛的题 赛时一直想着线段树 但连线段树的一些基本操作都没有搞懂 还是先不用线段树写了吧(虽然赛后提交正确是用线段树的)
两种操作
- 将小于k的所有能力值提升至k
- 将某一项能力值设定为b
每次遍历修改时间复杂度为n² 肯定不现实 此时转换思路 没必要每次都去修改 只需要按照操作先后顺序 记录此时的操作 所以在询问时肯定是使用for从1到q循环
对于操作1 只需要多开一个数组d 记录这个i下的设定的值
对于操作2 需要记录修改的值以及操作的时间 那如何进行呢? 多开一维就好了 所以一开始就用二维数组记录初始能力值 在操作2时对值进行修改 并且记录操作时间
然后从尾到头 开数组f记录d的最大值 此处从末尾遍历 确保在当前时间下的d数组的最大值
最后遍历整个数组 对比在这个时间的能力值和原先的能力值 输出较大值就结束了
PS:感觉有点混乱 其实就是根据操作时间记录了这个能力最后能到达的最大值 和原始值(或者修改值)之间的大小关系
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int MAX = 2e5 + 5;
ll tag[MAX][2], a[MAX];
ll d[MAX], f[MAX];
int n, m;
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
tag[i][1] = a[i];
}
cin >> m;
for (int i = 1; i <= m; ++i) {
int op;
cin >> op;
if (op == 1) {
cin >> d[i];
}
else {
int x, y;
cin >> x >> y;
tag[x][0] = i, tag[x][1] = y;
}
}
f[m] = d[m];
for (int i = m - 1; i >= 0; --i)
f[i] = max(f[i + 1], d[i]);
for (int i = 1; i <= n; ++i) {
cout << max(tag[i][1], f[tag[i][0]]) << " ";
}
}
把我第一次AC的线段树代码附上吧
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5 + 9;
ll a[N], tag[N << 2], t[N << 2];
int n, q;
void pushup(int o){
t[o] = min(t[o << 1], t[o << 1 | 1]);
}
void build(int s = 1, int e = n, int o = 1){
if(s == e){
t[o] = a[s];
return;
}
int mid = (s + e) >> 1;
build(s, mid, o << 1);
build(mid + 1, e, o << 1 | 1);
pushup(o);
}
void pushdown(int o){
if(t[o << 1] < tag[o] && tag[o] > tag[o << 1]){
t[o << 1] = tag[o];
tag[o << 1] = tag[o];
}
if(t[o << 1 | 1] < tag[o] && tag[o] > tag[o << 1 | 1]){
t[o << 1 | 1] = tag[o];
tag[o << 1 | 1] = tag[o];
}
tag[o] = 0;
}
void c_tag(ll x){
tag[1] = max(x, tag[1]);
}
void change(int s, int e, int o, int pos, int val){
if(s > pos || pos > e)return;
if(s == pos && pos == e){
t[o] = val;
tag[o] = 0;
return;
}
pushdown(o);
int mid = (s + e) >> 1;
change(s, mid, o << 1, pos, val);
change(mid + 1, e, o << 1 | 1, pos, val);
pushup(o);
}
//单点查询
ll quire(int pos, int s = 1, int e = n, int o = 1){
if(s > pos || pos > e)return 0;
if(s == e)return t[o];
pushdown(o);
int mid = (s + e) >> 1;
return quire(pos, s, mid, o << 1) + quire(pos, mid + 1, e, o << 1 | 1);
}
int main (){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1;i <= n; ++ i)cin >> a[i];
build();
cin >> q;
while(q--){
int op;cin >> op;
if(op == 1){
ll x;cin >> x;
c_tag(x);
}else{
int pos, val;cin >> pos >> val;
change(1, n, 1, pos, val);
}
}
for(int i = 1;i <= n; ++ i){
cout << quire(i) << ' ';
}
return 0;
}