HLG 1524 最大 (离散化线段树)

链接: http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1524


Description

给包含n个数的初始序列,A[1], A[2], ..., A[n]。
给q多个操作,操作如下:
1 a b v, 把[a, b] 的值改为v,即A[a] = A[a+1] = ... = A[b] = v。
2 a b, 查询[a, b] 之间的相同数的连续和最大值。

在[a, b]区间内,相同数的连续和最大值就是Sum(A[i], A[i+1], A[j]), a <= i <= j <= b,并且A[i] = A[i+1] = A[i+2] = A[i+3] = ... = A[j]。


Input

有多组测试数据,不超过5组测试数据。
对于每组测试数据,第一个为 n (n<=10^5),第二行为n个数,每个数的范围[0, 1000]。
第三行为 q (q<=10^5),表示查询的次数。
接下来有q个操作,格式如下:
1 a b v, 把[a, b] 的值改为v,即A[a] = A[a+1] = ... = A[b] = v。
2 a b, 查询[a, b] 之间的相同数的连续和最大值。
其中 1 <= a <= b <=n,0 <= v <= 1000.

Output
每组测试数据先输出一行"Case id:",id从1开始计数。
对于每个查询,输出一行,包含一个整数,为相同数的连续和最大值。

Sample Input

5
2 2 1 2 3
3
2 1 4
1 1 3 2
2 1 5
7
120 985 727 979 68 558 732
4
1 2 5 627
2 2 7
2 4 5
1 5 7 571

Sample Output

Case 1:
4
8
Case 2:
2508
1254


代码如下: (这代码当时把我弄疯了)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <limits.h>
#include <algorithm>
#define maxn 100005
#define RST(N)memset(N, 0, sizeof(N))
using namespace std;

int max(int a, int b) { return a > b ? a : b; }
int min(int a, int b) { return a < b ? a : b; }

int lva[maxn<<4];        // 最左面的值
int lnu[maxn<<4];        // 最左面的数的个数
int rva[maxn<<4];        // 最右面的值
int rnu[maxn<<4];        // 最右面的数的个数
int mva[maxn<<4];        // 区间最大连续值
int add[maxn<<4];        // 延迟标记
int v[maxn], re[100005];

void creat(int l, int r, int rt)
{
    add[rt] = -1;
    if(l == r) {
        lva[rt] = rva[rt] = v[l];
        lnu[rt] = rnu[rt] = 1;
        mva[rt] = v[l];
        return;
    }
    int m = (l+r) >> 1;
    creat(l, m, rt<<1);
    creat(m+1, r, rt<<1|1);
    lva[rt] = lva[rt<<1];
    lnu[rt] = lnu[rt<<1];
    rva[rt] = rva[rt<<1|1];
    rnu[rt] = rnu[rt<<1|1];
    if(lva[rt<<1]==lva[rt<<1|1] && lnu[rt<<1]==(m-l+1)) lnu[rt] += lnu[rt<<1|1];
    if(rva[rt<<1]==rva[rt<<1|1] && rnu[rt<<1|1]==r-m) rnu[rt] += rnu[rt<<1];
    mva[rt] = max(mva[rt<<1], mva[rt<<1|1]);
    if(rva[rt<<1] == lva[rt<<1|1]) {
        mva[rt] = max(mva[rt], rva[rt<<1]*rnu[rt<<1]+lva[rt<<1|1]*lnu[rt<<1|1]);
    }
}

void update(int L, int R, int c, int l, int r, int rt)
{
    if(L <= l && r <= R) {
        add[rt] = c;
        lva[rt] = rva[rt] = c;
        lnu[rt] = rnu[rt] = r-l+1;
        mva[rt] = c*(r-l+1);
        return;
    }
    int m = (l+r) >> 1;
    if(add[rt] != -1) {
        add[rt<<1] = add[rt<<1|1] = add[rt];
        lva[rt<<1] = rva[rt<<1] = lva[rt<<1|1] = rva[rt<<1|1] = add[rt];
        lnu[rt<<1] = rnu[rt<<1] = m-l+1;
        lnu[rt<<1|1] = rnu[rt<<1|1] = r - m;
        mva[rt<<1] = (m-l+1) * add[rt];
        mva[rt<<1|1] = (r-m) * add[rt];
        add[rt] = -1;
    }
    if(L <= m) update(L, R, c, l, m, rt<<1);
    if(R > m) update(L, R, c, m+1, r, rt<<1|1);
    lva[rt] = lva[rt<<1];
    lnu[rt] = lnu[rt<<1];
    rva[rt] = rva[rt<<1|1];
    rnu[rt] = rnu[rt<<1|1];
    if(lva[rt<<1] == lva[rt<<1|1] && lnu[rt<<1] == (m-l+1)) lnu[rt] += lnu[rt<<1|1];
    if(rva[rt<<1] == rva[rt<<1|1]&& rnu[rt<<1|1] == r-m) rnu[rt] += rnu[rt<<1];
    mva[rt] = max(mva[rt<<1], mva[rt<<1|1]);
    if(rva[rt<<1] == lva[rt<<1|1]) {
        mva[rt] = max(mva[rt], rva[rt<<1]*rnu[rt<<1]+lva[rt<<1|1]*lnu[rt<<1|1]);
    }
}

int query(int L, int R, int l, int r, int rt)
{
    if(L <= l && r <= R) return mva[rt];
    int m = (l+r) >> 1;
    if(add[rt] != -1) {
        add[rt<<1] = add[rt<<1|1] = add[rt];
        lva[rt<<1] = rva[rt<<1] = lva[rt<<1|1] = rva[rt<<1|1] = add[rt];
        lnu[rt<<1] = rnu[rt<<1] = m-l+1;
        lnu[rt<<1|1] = rnu[rt<<1|1] = r - m;
        mva[rt<<1] = (m-l+1) * add[rt];
        mva[rt<<1|1] = (r-m) * add[rt];
        add[rt] = -1;
    }
    if(R <= m) return query(L, R, l, m, rt<<1);
    else if(L > m) return query(L, R, m+1, r, rt<<1|1);
    else {
        int res = 0;
        if(rva[rt<<1] == lva[rt<<1|1])
            res = (min(rnu[rt<<1], m-L+1) + min(lnu[rt<<1|1], R-m)) * rva[rt<<1];
        return max(res, max(query(L, m, l, m, rt<<1), query(m+1, R, m+1, r, rt<<1|1)));
    }
}

int n, a, b, c, m, op, cas = 1, top = 0, tot;

void Init()
{
    for(int i=1; i<=n; i++) scanf("%d", &v[i]);
    creat(1, n, 1);
    scanf("%d", &m);
    tot = 0;
}

int main()
{
    while(~scanf("%d", &n)) {
        Init();
        printf("Case %d:\n", cas++);
        while(m--) {
            scanf("%d", &op);
            if(op == 1) {
                scanf("%d %d %d", &a, &b, &c);
                update(a, b, c, 1, n, 1);
            }else {
                scanf("%d %d", &a, &b);
                printf("%d\n", query(a, b, 1, n, 1));
            }
        }
    }
    return 0;
}



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