HDU 5306 Gorgeous Sequence 吉司机线段树

传送门

  详细的解读看这篇博客,因为他没贴代码,所以我贴一下代码并且说一下题目会卡啥。

  这题时间卡的非常死,我在网络上找了四篇博客,只有一篇可以AC,其余三篇全都TLE。

  首先就是读入,如果用IO优化的cin是会T掉的,我这边用的是一个快读的板子,有些人scanf和printf也能过,总之不要写IO优化的cin和cout。

  另外除了修改操作以外都是不需要pushup的,因为如果我们修改的时候覆盖到一个区间停止了,由于只有区min操作,所以当前区间维护的最大值只有可能比子区间更小,所以只需要把父节点的信息下传,而不需要把子区间的信息重新上传。

  mx表示区间最大值,md表示区间严格次大值,mcnt表示区间最大值出现的次数。

  另外自己实现一个三元运算符的min和max函数,某人说要比库函数自带的要快。

  AC代码如下。

#include <iostream>
#include <algorithm>
 

#define ll long long
const int N = 1e6 + 10;
#define ls(u) u << 1
#define rs(u) u << 1 | 1
const int INF = 0x3f3f3f3f;

const int LO = 1 << 20 | 1;
char buffer[LO], *S, *TT;
#define getchar() ((S==TT&&(TT=(S=buffer)+fread(buffer,1,LO,stdin),S==TT))?EOF:*S++)

namespace Fio {
    inline std::string sread() {
        std::string s = "";
        char e = getchar();
        while (!isdigit(e) && !isalpha(e) && e != '*') e = getchar();
        while (isdigit(e) || isalpha(e) || e == '*') s += e, e = getchar();
        return s;
    }
    
    inline int read() {
        int x = 0, y = 1;
        char c = getchar();
        while (!isdigit(c)) {
            if (c == '-') y = -1;
            c = getchar();
        }
        while (isdigit(c)) {
            x = (x << 3) + (x << 1) + (c ^ 48);
            c = getchar();
        }
        return x *= y;
    }
    
    inline ll readll() {
        ll x = 0, y = 1;
        char c = getchar();
        while (!isdigit(c)) {
            if (c == '-') y = -1;
            c = getchar();
        }
        while (isdigit(c)) {
            x = (x << 3) + (x << 1) + (c ^ 48);
            c = getchar();
        }
        return x *= y;
    }
    inline void write(ll x) {
        if (x < 0) x = -x, putchar('-');
        ll sta[35], top = 0;
        do sta[top++] = x % 10, x /= 10;
        while (x);
        while (top) putchar(sta[--top] + '0');
        putchar('\n');
    }
    
    inline void write(int x) {
        if (x < 0) x = -x, putchar('-');
        int sta[35], top = 0;
        do sta[top++] = x % 10, x /= 10;
        while (x);
        while (top) putchar(sta[--top] + '0');
        putchar('\n');
    }

} using namespace Fio;


int n , m, _;
int ans = INF;

int d1[] = {0, 0, 1, -1};
int d2[] = {1, -1, 0, 0};

int a[N];

int T[N << 2], mx[N << 2], md[N << 2], mcnt[N << 1];
ll sum[N << 2];

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

inline void pushup(int u){
    sum[u] = sum[u << 1] + sum[u << 1 | 1];
    if(mx[u << 1] > mx[u << 1 | 1]){
        mx[u] = mx[u << 1];
        mcnt[u] = mcnt[u << 1];
        md[u] = md[u << 1] > mx[u << 1 | 1] ? md[u << 1] : mx[u << 1 | 1];
    }else if(mx[u << 1] < mx[u << 1 | 1]){
        mx[u] = mx[u << 1 | 1];
        mcnt[u] = mcnt[u << 1 | 1];
        md[u] = md[u << 1 | 1] >  mx[u << 1] ? md[u << 1 | 1] : mx[u << 1];
    }else{
        mx[u] = mx[u << 1];
        mcnt[u] = mcnt[u << 1] + mcnt[u << 1 | 1];
        md[u] = md[u << 1] > md[u << 1 | 1] ? md[u << 1] : md[u << 1 | 1];
    }
}

inline void build_tree(int u, int l, int r){
    if(l == r){
        mx[u] = sum[u] = a[l];
        md[u] = -INF;
        mcnt[u] = 1;
        return ;
    }
    
    int mid = l + r >> 1;
    
    build_tree(u << 1, l, mid);
    build_tree(u << 1 | 1, mid + 1, r);
    
    pushup(u);
}

inline void pushdown(int u){
    int ls = u << 1, rs = u << 1 | 1;
    if(mx[ls] > mx[u] && md[ls] <  mx[u]){
        sum[ls] -= 1ll * (mx[ls] - mx[u]) * mcnt[ls];
        mx[ls] = mx[u];            
    }
    if(mx[rs] > mx[u] && md[rs] < mx[u]){
        sum[rs] -= 1ll * (mx[rs] - mx[u]) * mcnt[rs];
        mx[rs] = mx[u];        
    }
}

inline void modify(int u, int L, int R, int l, int r, int x){
    if(mx[u] <= x)    return ;
    if(L >= l && R <= r && md[u] < x){
        sum[u] -= 1ll * (mx[u] - x) * mcnt[u];
        mx[u] = x;
        return ;
    }
    
    pushdown(u);
    
    int mid = L + R >> 1;
    if(l <= mid)    modify(u << 1, L, mid, l, r, x);
    if(r > mid)    modify(u << 1 | 1, mid + 1, R, l, r, x);
    
    pushup(u);
}

inline int querymx(int u, int L, int R, int l, int r){
    if(L >= l && R <= r)    return mx[u];
    
    pushdown(u);
    
    int mid = L + R >> 1;
    int res = 0;
    if(l <= mid){
        int tmp = querymx(u << 1, L, mid, l, r);
        res = res > tmp ? res : tmp;
    }    
    
    if(r > mid){
        int tmp = querymx(u << 1 | 1, mid + 1, R, l, r);
        res = res > tmp ? res : tmp;
    }
    
    return res;
}

inline ll querysum(int u, int L, int R, int l, int r){
    if(L >= l && R <= r)    return sum[u];
    
    pushdown(u);
    
    int mid = L + R >> 1;
    ll res = 0;
    if(l <= mid)    res += querysum(u << 1, L, mid, l, r);
    
    if(r > mid)    res += querysum(u << 1 | 1, mid + 1, R, l, r);
    
    return res;
}

inline void solve(){
    n = read(), m = read();
    for(int i = 1; i <= n; i ++)    a[i] = read();
    
    build_tree(1, 1, n);
    
    while(m --){
        int op, l, r, x;
        op = read(), l = read(), r = read();
        if(op == 0){
            x = read();
            modify(1, 1, n, l, r, x);
        }else if(op == 1){
            write(querymx(1, 1, n, l, r));
        }else{
            write(querysum(1, 1, n, l, r));
        }
    }
}

int main(){
       
    _ = 1;
       _ = read();
    while(_ --)
        solve();

    return 0;
}
posted @ 2023-03-23 11:32  春始于雪之下  阅读(65)  评论(0编辑  收藏  举报