AHOI2014/JSOI2014 奇怪的计算器

题目传送门

好久没写博客了,咕咕咕


一开始自己想了想,搞了一颗线段树,结果\(4\)个标记,写到自闭
打开题解,仿佛打开了新世界的大门,让我知道了自己代码的丑陋


将所有的要进行操作的数从小到大排序,建一颗线段树,对它们进行统一修改

用线段树维护区间最大值和最小值,且支持区间加减、区间乘、区间加原数的\(x\)倍和区间覆盖
一开始我用了\(4\)个标记维护,然后自闭了,发现题解构建了一个函数,大大节省了编程的复杂度
对线段树的一个元素\(x\),设计这样一个更新函数:\(f(k1,k2, k3) = x \times k1 + y \times 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;
}
posted @ 2019-11-14 11:06  MorsLin  阅读(230)  评论(0编辑  收藏  举报