UOJ164 V 线段树历史查询

题目:

第一行两个数:n,m。

接下来一行 n 个数,第 i个数表示初始时第i个水箱内有ai m3的水。

接下来 m 行中,第 i行第一个数ti表示操作类型:

若 ti=1,则接下来三个整数li,ri,xi,表示打开编号在[li,ri]中的所有水箱的上方接口xixi 秒。

若 ti=2,则接下来三个整数li,ri,xi,表示打开编号在[li,ri]中的所有水箱的下方接口xixi 秒。

若 ti=3,则接下来三个整数li,ri,xi,表示将编号在[li,ri]中的所有水箱与大海连接,使这些水箱中都恰有xi m3的水。

若 ti=4,则接下来一个整数yi,表示测量在第yi 个水箱的上下方接口处接上一个电动势为 1 V   的电源时通过电源的电流。

若 ti=5,则接下来一个整数yi,表示测量此时在第yi 个水箱中的水渍高度。
思路:

各用一个二元组保存现在和历史的最大值,其中(x,y)代表加上x后对y取最大值,下传标记时将标记加起来即可:

(x, y) + (u, v) = (x + u, max(y + u, v))

注意(x,y)是老标记,(u,v)是下传的标记(开始重载了运算符又没注意顺序,搞反了调了好久……)

考虑加法操作就是将(x, -INF)下传,区间修改就是将(-INF, x)下传。

#include 
#include 
#include 
#include 

#define For(i,j,k) for(int i = j;i <= k;i++)
#define Forr(i,j,k) for(int i = j;i >= k;i--)
#define Set(i,j) memset(i, j, sizeof(i))

#define lc (h << 1)
#define rc (h << 1 | 1)
#define M ((L + R) >> 1)

#define x first
#define y second

using namespace std;

typedef long long LL;
typedef pair PII;

const LL INF = 1e18;
const int N = 5e5 + 10;

PII operator + (PII A, PII B){
    return PII(max(A.x + B.x, -INF), max(A.y + B.x, B.y));
}

PII max(PII A, PII B){
    return PII(max(A.x, B.x), max(A.y, B.y));
}

struct Segment_Tree{
    PII now[N<<2], ever[N<<2];

    void Add(int h, int ch){
        ever[ch] = max(now[ch] + ever[h], ever[ch]);
        now[ch] = now[ch] + now[h];
    }

    void pushdown(int h){
        Add(h, lc), Add(h, rc);
        now[h] = ever[h] = PII(0, 0);
    }

    void Create(int h, int L, int R){
        if(L == R){
            scanf("%lld", &now[h].x), now[h].y = -INF;
            ever[h] = now[h];
            return;
        }
        now[h] = ever[h] = PII(0, 0);
        Create(lc, L, M), Create(rc, M+1, R);
    }

    void Modify(int h, int L, int R, int l, int r, const PII& v){
        if(l <= L && R <= r){
            now[h] = now[h] + v;
            ever[h] = max(ever[h], now[h]);
        }
        else{
            pushdown(h);
            if(l <= M) Modify(lc, L, M, l, r, v);
            if(r > M) Modify(rc, M+1, R, l, r, v);
        } 
    }

    LL Query(int h, int L, int R, int pos, bool ty){
        if(L == R) return ty ? max(now[h].x, now[h].y) : max(ever[h].x, ever[h].y);
        pushdown(h);
        if(pos <= M) return Query(lc, L, M, pos, ty);
        else return Query(rc, M+1, R, pos, ty);
    }

}T;

int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    T.Create(1, 1, n);
    while(m--){
        int ty, l, r, x;
        scanf("%d", &ty);
        if(ty <= 3){
            scanf("%d%d%d", &l, &r, &x);
            if(ty == 1) T.Modify(1, 1, n, l, r, PII(x, -INF));
            if(ty == 2) T.Modify(1, 1, n, l, r, PII(-x, -INF));
            if(ty == 3) T.Modify(1, 1, n, l, r, PII(-INF, x));
        }
        else scanf("%d", &x), printf("%lld\n", T.Query(1, 1, n, x, ty == 4));
    }
    return 0;
}

你可能感兴趣的:(线段树)