[CSU-1913] 一条大笨龙送礼物 线段树 二分答案

今天考试的T3题目 好像也不是很难 但是蒟蒻的我就是想不到啊哎

我也不知道出题人怎么想到的

考虑二分答案 设当前二分的答案为 m i d 则把序列中大于等于 m i d 的位置设为 1 , 其他位置设为 0 ,放到一颗线段树上,那么 1 操作是让大的值在两边, 那么就可以转化为两端区间赋值为 1 ,中间区间赋值为 0 ,最后如果询问的位置 k 的答案为 1 表示当前答案可行,2操作看了题解也看不懂,感觉自己陷入了一点思维误区,总想着把这个东西可持久化..实际上用一个栈把这些操作存下来,如果遇到一个 2 操作你就把前面的都删除就好了, 这样总的复杂度是两个 l o g 的, 就可以通过此题啦.
链接

Codes

#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)

using namespace std;

const int maxn = 5e5 + 10;
int n, m, q, cnt, a[maxn];

struct Query {
    int opt, x, y; 
}Q[maxn];

struct Segment_Tree {
#define mid ((l + r) >> 1)
#define ls (bh << 1)
#define rs (ls | 1)
    int s[maxn << 2], lazy[maxn << 2];

    void pushup(int bh) {
        s[bh] = s[ls] + s[rs];
    }

    void pushdown(int bh, int l, int r) {
        if(lazy[bh] != -1) {
            lazy[ls] = lazy[rs] = lazy[bh];
            s[ls] = lazy[bh] * (mid - l + 1);
            s[rs] = lazy[bh] * (r - mid);
            lazy[bh] = -1;
        }
    }

    void build(int bh, int l, int r, int p) {
        lazy[bh] = -1;
        if(l == r) 
            s[bh] = (a[l] >= p);
        else {
            build(ls, l, mid, p);
            build(rs, mid + 1, r, p);
            pushup(bh);
        }
    }

    void update(int bh, int l, int r, int x, int y, int z) {
        if(x <= l && r <= y) {
            s[bh] = (r - l + 1) * z;
            lazy[bh] = z;
        }
        else {
            pushdown(bh, l, r);
            if(x <= mid) update(ls, l, mid, x, y, z);
            if(y > mid) update(rs, mid + 1, r, x, y, z);
            pushup(bh);
        }
    }

    int query(int bh, int l, int r, int x, int y) {
        int res = 0;
        if(x <= l && r <= y)
            res += s[bh];
        else {
            pushdown(bh, l, r);
            if(x <= mid) res += query(ls, l, mid, x, y);
            if(y > mid) res += query(rs, mid + 1, r, x, y);
        }
        return res;
    }

}T;

void File() {
    freopen("coach.in", "r", stdin);
    freopen("coach.out", "w", stdout);
}

void Init() {
    int x, y, z;
    scanf("%d%d%d", &n, &m, &q);
    For(i, 1, n) 
        scanf("%d", &a[i]);
    For(i, 1, m) {
        scanf("%d%d", &x, &y);
        if(x == 1) {
            scanf("%d", &z);
            Q[++ cnt] = (Query){x, y, z};
        }
        else cnt = max(0, cnt - y);
    }
}

void Solve() {
    int ans, l = 1, r = 2e5;
    int L1, L2, R1, R2, sum;
    while(l <= r) {
        T.build(1, 1, n, mid);
        For(i, 1, cnt) {
            sum = T.query(1, 1, n, Q[i].x, Q[i].y);
            if(sum == 0 || sum == (Q[i].y - Q[i].x + 1)) 
                continue;
            L1 = Q[i].x, R1 = Q[i].x + sum / 2 + sum % 2 - 1;
            L2 = Q[i].y - sum / 2 + 1, R2 = Q[i].y; 
            T.update(1, 1, n, L1, R1, 1);
            T.update(1, 1, n, L2, R2, 1);
            if(R1 + 1 <= L2 - 1)
                T.update(1, 1, n, R1 + 1, L2 - 1, 0);
        }
        if(T.query(1, 1, n, q, q) == 1) 
            ans = mid, l = mid + 1;
        else r = mid - 1;
    }
    printf("%d\n", ans);
}

int main() {
    File();
    Init();
    Solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/81413603