好久没写博客了,咕咕咕
一开始自己想了想,搞了一颗线段树,结果(4)个标记,写到自闭
打开题解,仿佛打开了新世界的大门,让我知道了自己代码的丑陋
将所有的要进行操作的数从小到大排序,建一颗线段树,对它们进行统一修改
用线段树维护区间最大值和最小值,且支持区间加减、区间乘、区间加原数的(x)倍和区间覆盖
一开始我用了(4)个标记维护,然后自闭了,发现题解构建了一个函数,大大节省了编程的复杂度
对线段树的一个元素(x),设计这样一个更新函数:(f(k1,k2, k3) = x imes k1 + y imes k2 + k3),其中(y)是最初输入进来的数
然后区间加:(f(1, 0, add)),区间乘:(f(mul,0, 0)),区间加原数:(f(1, addx, 0)),区间覆盖:(f(0,0,x))
这样就好写多了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
#define mid ((l + r) >> 1)
#define ls p << 1
#define rs p << 1 | 1
using namespace std;
LL read() {
LL k = 0, f = 1; char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
k = k * 10 + c - 48, c = getchar();
return k * f;
}
struct zzz {
char flag; LL x;
}opt[100010];
struct hhh {
int l, r; LL max, min, k1, k2, k3;
}tree[100010 << 2];
struct jjj {
int pos; LL x;
}a[100010];
void up(int p) {
tree[p].max = tree[rs].max;
tree[p].min = tree[ls].min;
}
void build(int l, int r, int p) {
tree[p].l = l, tree[p].r = r, tree[p].k1 = 1;
if(l == r) {
tree[p].max = tree[p].min = a[l].x; return ;
}
build(l, mid, ls); build(mid+1, r, rs);
up(p);
}
void pushnow(int p, LL k1, LL k2, LL k3) {
tree[p].k1 *= k1, tree[p].k2 = tree[p].k2 * k1 + k2, tree[p].k3 = tree[p].k3 * k1 + k3;
tree[p].max = tree[p].max * k1 + a[tree[p].r].x * k2 + k3;
tree[p].min = tree[p].min * k1 + a[tree[p].l].x * k2 + k3;
}
void down(int p) {
hhh &x = tree[p];
pushnow(ls, x.k1, x.k2, x.k3),
pushnow(rs, x.k1, x.k2, x.k3);
x.k1 = 1, x.k2 = x.k3 = 0;
}
void update_low(int p, int k) {
if(tree[p].l == tree[p].r) {
pushnow(p, 0, 0, k); return ;
}
down(p);
if(tree[ls].max > k) pushnow(rs, 0, 0, k), update_low(ls, k);
else update_low(rs, k);
up(p);
}
void update_up(int p, int k) {
if(tree[p].l == tree[p].r) {
pushnow(p, 0, 0, k); return ;
}
down(p);
if(tree[rs].min < k) pushnow(ls, 0, 0, k), update_up(rs, k);
else update_up(ls, k);
up(p);
}
LL ans[100010];
void query(int p) {
//cout << tree[p].l << ' ' << tree[p].r << endl;
if(tree[p].l == tree[p].r) {
//cout << tree[p].l << endl;
ans[a[tree[p].l].pos] = tree[p].min;
return ;
}
down(p);
query(ls), query(rs);
}
bool cmp(jjj x, jjj y) {
return x.x < y.x;
}
int main() {
int m = read(), l = read(), r = read();
for(int i = 1; i <= m; ++i) {
char c = getchar();
while(c != '+' && c != '-' && c != '*' && c != '@') c = getchar();
opt[i].flag = c, opt[i].x = read();
}
int n = read();
for(int i = 1; i <= n; ++i) a[i].pos = i, a[i].x = read();
sort(a+1, a+n+1, cmp);
build(1, n, 1);
for(int i = 1; i <= m; ++i) {
if(opt[i].flag == '+')
pushnow(1, 1, 0, opt[i].x);
else if(opt[i].flag == '-')
pushnow(1, 1, 0, -opt[i].x);
else if(opt[i].flag == '*')
pushnow(1, opt[i].x, 0, 0);
else if(opt[i].flag == '@')
pushnow(1, 1, opt[i].x, 0);
if(tree[1].max > r) update_low(1, r);
if(tree[1].min < l) update_up(1, l);
}
query(1);
for(int i = 1; i <= n; ++i) cout << ans[i] << endl;
return 0;
}