Codeforces 1146E

题意:
给出一个序列,有两种操作:

  • \(>\;x\) 将大于\(x\)的数全都取负
  • \(<\;x\) 将小于\(x\)的数全都取负
    最后输出序列中的所有数最后的状态

思路:
我们先考虑对于一个数来说,它最后的状态只取决于它初始的时候是哪个数,而跟它所处的位置无关。
我们注意到序列中的数的范围是\([-10^{5}, 10^5]\),那么我们只需要处理出每个数在经过\(q\)次操作后的状态是什么,最后查表就好了。
我们定义一个状态\(1\)和\(-1\),分别表示一个数的当前状态是取负了还是没有取负。

我们以\(>\;x\)这个操作为例:

  1. 如果\(x > 0\),那么也就是说\([x + 1, 10^5]\)这部分的数的状态肯定是-1, 并且\([-10^5, -x - 1]\)这部分数的状态肯定是\(1\),而不用管它们之前是什么状态,那么直接区间赋值就好了
  2. 如果\(x < 0\),那么\([x + 1, -x - 1]\)这部分数的状态是反转,\([-x, 10^5]\)这部分数的状态肯定是\(-1\),\([-10^5, x]\)这部分数的状态肯定是\(1\),那么区间反转就好了
    用线段树维护区间赋值和区间反转就可以了,同理\(<\;x\)的操作也类似处理
#include <bits/stdc++.h>
using namespace std;

#define N 200010
#define D 100005
int n, q, a[N];

struct SEG {
    struct node {
        int x, lazy[2];   
        node () {
            x = 1;
            lazy[0] = 0;
            lazy[1] = 1; 
        }
        void add1(int v) {
            lazy[1] = 1;
            lazy[0] = v;
            x = v;
        }
        void add2(int v) {
            x *= v; 
            if (lazy[0] != 0) {
                lazy[0] *= v;
            } else {
                lazy[1] *= v;
            }
        }
    }t[N << 2];
    void build(int id, int l,int r) {
        if (l == r) {
            t[id] = node();
            return;
        }
        int mid = (l + r) >> 1;
        build(id << 1, l, mid);
        build(id << 1 | 1, mid + 1, r);
    }
    void pushdown(int id) {
        if (t[id].lazy[1] != 1) {
            t[id << 1].add2(t[id].lazy[1]);
            t[id << 1 | 1].add2(t[id].lazy[1]);
            t[id].lazy[1] = 1;
        }
        if (t[id].lazy[0] != 0) {
            t[id << 1].add1(t[id].lazy[0]);
            t[id << 1 | 1].add1(t[id].lazy[0]);
            t[id].lazy[0] = 0;
        }
    }
    void update1(int id, int l ,int r, int ql, int qr, int v) {
        if (ql > qr) {
            return;
        }
        if (l >= ql && r <= qr) {
            t[id].add1(v);
            return;
        }
        int mid = (l + r) >> 1;
        pushdown(id);
        if (ql <= mid) update1(id << 1, l, mid, ql, qr, v);
        if (qr > mid) update1(id << 1 | 1, mid + 1, r, ql, qr, v);
    }
    void update2(int id, int l, int r, int ql, int qr, int v) {
        if (ql > qr) {
            return;
        }
        if (l >= ql && r <= qr) {
            t[id].add2(v);
            return;
        }
        int mid = (l + r) >> 1;
        pushdown(id);
        if (ql <= mid) update2(id << 1, l, mid, ql, qr, v);
        if (qr > mid) update2(id << 1 | 1, mid + 1, r, ql, qr, v);
    }
    int query(int id, int l, int r, int pos) {
        if (l == r) {
            return t[id].x;
        }
        int mid = (l + r) >> 1;
        pushdown(id);
        if (pos <= mid) return query(id << 1, l, mid, pos);
        else return query(id << 1 | 1, mid + 1, r, pos);
    }
}seg;

int main() {
    while (scanf("%d%d", &n, &q) != EOF) {
        for (int i = 1; i <= n; ++i) {
            scanf("%d", a + i);
        }
        seg.build(1, 1, 2 * D);
        char op[10]; int x;
        while (q--) {
            scanf("%s%d", op, &x);
            switch(op[0]) {
                case '>' :
                    if (x < 0) {
                        seg.update2(1, 1, 2 * D, x + 1 + D, -x - 1 + D, -1);
                        seg.update1(1, 1, 2 * D, -100000 + D, x + D, 1);
                        seg.update1(1, 1, 2 * D, -x + D, 100000 + D, -1);
                    } else {
                        seg.update1(1, 1, 2 * D, x + 1 + D, 100000 + D, -1);
                        seg.update1(1, 1, 2 * D, -100000 + D, -x - 1 + D, 1);
                    }
                    break;
                case '<' :
                    if (x > 0) {
                        seg.update2(1, 1, 2 * D, -x + 1 + D, x - 1 + D, -1);
                        seg.update1(1, 1, 2 * D, x + D, 100000 + D, 1);
                        seg.update1(1, 1, 2 * D,  -100000 + D, -x + D, -1); 
                    } else {
                        seg.update1(1, 1, 2 * D, -100000 + D, x - 1 + D, -1);
                        seg.update1(1, 1, 2 * D, -x + 1 + D, 100000 + D, 1);
                    }
                    break; 
                default : 
                    assert(0);  
            }
        //  for (int i = -5; i <= 5; ++i) {
        //      printf("%d%c", seg.query(1, 1, 2 * D, i + D), " \n"[i == 5]);
        //  }
        }
        for (int i = 1; i <= n; ++i) {
            printf("%d%c", a[i] * seg.query(1, 1, 2 * D, a[i] + D), " \n"[i == n]);
        }
    }
    return 0;
}
上一篇:[SDOI2009]SuperGCD


下一篇:乘积最大