题意:
给定数组a[n],然后m个操作,每次操作给出一个数x,数组中小于等于x的数都要加上x。最后输出所有的a[i]。
两种解法,一种线段树,另一种是优先队列加一些神奇的优化。
线段树:
维护区间的最小值与最大值,如果最大值小于等于x,则直接修改区间,如果最小值大于x,则直接返回。
最后输出的是每个父亲节点的值。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 5, mod = 998244353;
int a[N], maxx[N * 4], minn[N * 4], tag[N * 4];
int x;
void build(int now, int l, int r)
{
if (l >= r) {
maxx[now] = minn[now] = a[l];
return;
}
int mid = (l + r) / 2;
int chl = 2 * now, chr = 2 * now + 1;
build(chl, l, mid);
build(chr, mid + 1, r);
maxx[now] = max(maxx[chl], maxx[chr]);
minn[now] = min(minn[chl], minn[chr]);
}
void down(int now, int l, int r)
{
int chl = 2 * now, chr = 2 * now + 1;
tag[chl] += tag[now] ,tag[chr] += tag[now];
maxx[chl] += tag[now], maxx[chr] += tag[now];
minn[chl] += tag[now], minn[chr] += tag[now];
tag[now] = 0;
}
void xg(int now, int l, int r)
{
if (maxx[now] <= x) {
maxx[now] += x;
minn[now] += x;
tag[now] += x;
return;
}
else if (minn[now] > x) return;
//else if (l >= r) return;
else {
down(now, l, r);
int mid = (l + r) / 2;
int chl = 2 * now, chr = 2 * now + 1;
xg(chl, l, mid);
xg(chr, mid + 1, r);
maxx[now] = max(maxx[chl], maxx[chr]);
minn[now] = min(minn[chl], minn[chr]);
}
}
void print(int now, int l, int r)
{
if (l >= r) {
printf("%lld ", maxx[now]);
return;
}
down(now, l, r);
int mid = (l + r) / 2;
int chl = 2 * now, chr = 2 * now + 1;
print(chl, l, mid);
print(chr, mid + 1, r);
}
signed main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
build(1, 1, n);
for (int i = 1; i <= m; i++) {
scanf("%lld", &x);
xg(1, 1, n);
}
print(1, 1, n);
return 0;
}
优先队列:
如果所有元素为1。
x=1,变成2。
x=2,变成4。
x=4,变成8。
x=8,变成16。
所以数组里的数最多被加log级别的次数,可以使用看似暴力实则不暴力的优先队列。
这里的优化是,如果x=0,那么加了相当于没加,而且还要访问一遍所有的a[i],所以当x=0时要continue。还有一个优化是,pop优先队列的元素后,先不要急着马上push新元素进去,将新元素暂时缓存一个vecotr里,等pop完了再将vector的元素push进去。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 5, mod = 998244353;
int b[N];
struct node {
int val, pos;
bool operator < (const node &k) const {
if (val != k.val) return val > k.val;
return pos < k.pos;
}
} a;
priority_queue<node> q;
vector<node> v;
signed main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
int x;
scanf("%lld", &x);
q.push({x, i});
}
for (int i = 1; i <= m; i++) {
int x;
scanf("%lld", &x);
if (x == 0) continue;
while(!q.empty() && q.top().val <= x) {
v.push_back({q.top().val + x, q.top().pos});
q.pop();
}
int len = v.size();
for (int j = 0; j < len; j++) q.push(v[j]);
v.clear();
}
while(!q.empty()) {
b[q.top().pos] = q.top().val;
q.pop();
}
for (int i = 1; i <= n; i++) printf("%lld ", b[i]);
return 0;
}