BZOJ4355: Play with sequence(吉司机线段树)

题意

题目链接

Sol

传说中的吉司机线段树??感觉和BZOJ冒险那题差不多,就是强行剪枝。。。

这题最坑的地方在于对于操作1,$C >= 0$, 操作2中需要对0取max,$a[i] >= 0$,这不就是统计最小值出现的次数么??

按照套路

维护好区间赋值标记 / 区间加法标记 / 区间max标记 / 区间最小值 / 区间最小值出现的次数 / 区间次小值

对于第二个操作就拆成区间加 和 区间max

区间max是一个很神奇的操作

设当前加入的数为val

若val>=mn,那该操作对该区间无影响

若se < val < mn,该操作只会对次小值产生影响,因为对其他的标记均不会产生影响,因此打一个额外的标记即可

否则暴力递归

时间复杂度:$O(n log^2n)$??

另外这东西可以做区间加 / 查询历史版本,前者维护一下标记就行,,后者嘛,,,等长大了再研究吧qwq

#include<cstdio>
#include<algorithm>
#define LL long long 
//#define int long long 
using namespace std;
const int MAXN = 3 * 1e5 + 10;
const LL INF = 1e10 +10;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
#define ls k << 1
#define rs k << 1 | 1
int N, Q;
int a[MAXN];
struct Node {
    int l, r, siz, cnt;
    LL Mx, add, mn, se, cov;
}T[MAXN << 2];
void update(int k) {
    //T[k].mn = min(T[ls].mn, T[rs].mn);
    if(T[ls].mn < T[rs].mn)      T[k].cnt = T[ls].cnt, T[k].mn = T[ls].mn, T[k].se = min(T[rs].mn, T[ls].se);
    else if(T[ls].mn > T[rs].mn) T[k].cnt = T[rs].cnt, T[k].mn = T[rs].mn, T[k].se = min(T[ls].mn, T[rs].se);
    else              T[k].cnt = T[ls].cnt + T[rs].cnt, T[k].mn = T[ls].mn, T[k].se = min(T[ls].se, T[rs].se);
}
void MemP(int k, LL val) {
    T[k].cov = val;
    T[k].cnt = T[k].siz;
    T[k].se = INF;
    T[k].Mx = -INF;
    T[k].add = 0;
    T[k].mn = val;
}
void AddP(int k, LL val) {
    if(T[k].se != INF)  T[k].se += val;
    if(T[k].Mx != -INF) T[k].Mx += val;
    T[k].mn += val;
    T[k].add += val;
}
void MaxP(int k, LL val) {
    T[k].mn = max(T[k].mn, val);//
    T[k].Mx = max(T[k].Mx, val);
}
void pushdown(int k) {
    if(T[k].cov != INF) MemP(ls, T[k].cov), MemP(rs, T[k].cov), T[k].cov = INF;
    if(T[k].add) AddP(ls, T[k].add), AddP(rs, T[k].add), T[k].add = 0;
    if(T[k].Mx != -INF) MaxP(ls, T[k].Mx), MaxP(rs, T[k].Mx), T[k].Mx = -INF;
}
void Build(int k, int ll, int rr) {
    T[k] = (Node) {ll, rr, rr - ll + 1, 0, -INF, 0, 0, INF, INF};
    if(ll == rr) {
        T[k].mn = a[ll]; T[k].cnt = 1;
        return ;
    }
    int mid = T[k].l + T[k].r >> 1;
    Build(ls, ll, mid); Build(rs, mid + 1, rr);
    update(k);
}
void IntMem(int k, int ll, int rr, LL val) {
    if(ll <= T[k].l && T[k].r <= rr) {MemP(k, val); return ;}
    pushdown(k);
    int mid = T[k].l + T[k].r >> 1;
    if(ll <= mid) IntMem(ls, ll, rr, val); 
    if(rr >  mid) IntMem(rs, ll, rr, val);
    update(k);
}
void IntAdd(int k, int ll, int rr, LL val) {
    if(ll <= T[k].l && T[k].r <= rr) {AddP(k, val); return ;}
    pushdown(k);
    int mid = T[k].l + T[k].r >> 1;
    if(ll <= mid) IntAdd(ls, ll, rr, val);
    if(rr >  mid) IntAdd(rs, ll, rr, val);
    update(k);
}
void IntMax(int k, int ll, int rr, LL val) {
    if(val <= T[k].mn) return ;
    if(ll <= T[k].l && T[k].r <= rr && T[k].se > val) {//tag
        MaxP(k, val); 
        return ;
    }
    int mid = T[k].l + T[k].r >> 1;
    pushdown(k);
    if(ll <= mid) IntMax(ls, ll, rr, val); 
    if(rr >  mid) IntMax(rs, ll, rr, val);
    update(k);
}
LL Query(int k, int ll, int rr) {
    // int ans = 0;
    if(ll <= T[k].l && T[k].r <= rr) 
        return (T[k].mn == 0 ? T[k].cnt : 0);
    pushdown(k);
    int mid = T[k].l + T[k].r >> 1;
    if(ll > mid) return Query(rs, ll, rr);
    else if(rr <= mid) return Query(ls, ll, rr);
    else return Query(ls, ll, rr) + Query(rs, ll, rr);
}
main() {
    // freopen("4355.in", "r", stdin);
    // freopen("4355.out", "w", stdout);
    N = read(); Q = read();
    for(int i = 1; i <= N; i++) a[i] = read();
    Build(1, 1, N);
    while(Q--) {
        int opt = read(), l = read(), r = read(), val;
        if(opt == 3) printf("%d\n", Query(1, l, r));
        else {
            val = read();
            if(opt == 1) IntMem(1, l, r, val);
            else {
                IntAdd(1, l, r, val);
                IntMax(1, l, r, 0);
            }
        }
    }
    return 0;
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏CaiRui

Mysql-7-mysql函数

1.数学函数   用来处理数值数据方面的运算,主要的数学函数有:绝对值函数,三角函数,对数函数,随机函数。使用数学函数过程中,如果有错误产生,该函数会返回nul...

2077
来自专栏书山有路勤为径

二分查找

已知一个排序数组A,如A= [-1,2,5,20,90,100,207,800] 另外一个乱序数组B,如B =[50,90,3,-1,207,80] 求B中...

894
来自专栏软件开发 -- 分享 互助 成长

数据库的规范化

一、基础概念 实体:现实世界中客观存在并可以被区别的事物。比如“一个学生”、“一本书”、“一门课”等。 属性:教科书上解释为:“实体所具有的某一特性”,由此可见...

1776
来自专栏ml

C/C++ 一段代码区分数组指针|指针数组|函数指针|函数指针数组

1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<windows.h> 4 /* 举列子说明什么是...

2915
来自专栏函数式编程语言及工具

Scalaz(52)- scalaz-stream: 并行运算-parallel processing concurrently by merging

   如果scalaz-stream真的是一个实用的数据流编程工具库的话,那它应该能处理同时从多个数据源获取数据以及把数据同时送到多个终点(Sink),最重要的...

2078
来自专栏码匠的流水账

聊聊flink的CheckpointedFunction

flink-streaming-java_2.11-1.7.0-sources.jar!/org/apache/flink/streaming/api/chec...

1694
来自专栏Java 源码分析

Java位操作

     无论说是在哪一门计算机语言,位操作运算对于计算机来说肯定是最高效的,因为计算机的底层是按就是二进制,而位操作就是为了节省开销,加快程序的执行速度,以及...

3558
来自专栏分布式系统进阶

Librdkafka的基础数据结构 1 --- 队列

两个元素: tqh_first: 指向队列的第一个成员; tqh_last: 存的是队列里的最后一个元素的 next指针的变量地址, 这个二级指针太有用了,...

1022
来自专栏NetCore

解读C#中的正则表达式

 多少年来,许多的编程语言和工具都包含对正则表达式的支持,.NET基础类库中包含有一个名字空间和一系列可以充分发挥规则表达式威力的类,而且它们也都与未...

2317
来自专栏移动开发面面观

快速排序法及优化

1684

扫码关注云+社区

领取腾讯云代金券