loj6029 「雅礼集训 2017 Day1」市场

传送门:https://loj.ac/problem/6029

【题解】

考虑如果有一些近似连续的段

比如 2 2 2 3 3 3,考虑在除3意义下,变成0 0 0 1 1 1,相当于整体-2

又:区间增加很容易造成这种段,所以我们猜测可以暴力维护

用一棵线段树即可。(好像真的能暴力维护啊 我不知道怎么证明复杂度)

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 4e5 + 10;
const int mod = 1e9+7;

# define RG register
# define ST static

int n, a[M];
struct SMT {
    ll mx[M], mi[M], s[M], tag[M];
    # define ls (x<<1)
    # define rs (x<<1|1)
    inline void up(int x) {
        s[x] = s[ls] + s[rs];
        mx[x] = max(mx[ls], mx[rs]);
        mi[x] = min(mi[ls], mi[rs]);
    }
    inline void pushtag(int x, ll tg, int len) {
        mx[x] += tg;
        mi[x] += tg;
        s[x] += tg*len;
        tag[x] += tg;
    }
    inline void down(int x, int l, int r) {
        if(tag[x] == 0) return ;
        int mid = l+r>>1;
        pushtag(ls, tag[x], mid-l+1);
        pushtag(rs, tag[x], r-mid);
        tag[x] = 0;
    }
    inline void build(int x, int l, int r) {
        tag[x] = 0;
        if(l == r) {
            mx[x] = mi[x] = s[x] = a[l];
            return ;
        }
        int mid = l+r>>1;
        build(ls, l, mid);
        build(rs, mid+1, r);
        up(x);
    }
    inline void edt(int x, int l, int r, int L, int R, int c) {
        if(L <= l && r <= R) {
            pushtag(x, c, r-l+1);
            return ;
        }
        down(x, l, r);
        int mid = l+r>>1;
        if(L <= mid) edt(ls, l, mid, L, R, c);
        if(R > mid) edt(rs, mid+1, r, L, R, c);
        up(x);
    }
    inline void div(int x, int l, int r, int L, int R, int d) {
        if(L <= l && r <= R) {
            ll A, B;
            if(mi[x] < 0) A = (mi[x] - d + 1) / d;
            else A = mi[x] / d;
            if(mx[x] < 0) B = (mx[x] - d + 1) / d;
            else B = mx[x] / d;
            if(mi[x] - A == mx[x] - B) {
                pushtag(x, A - mi[x], r-l+1);
                return ;
            }
        }
        down(x, l, r);
        int mid = l+r>>1;
        if(L <= mid) div(ls, l, mid, L, R, d);
        if(R > mid) div(rs, mid+1, r, L, R, d);
        up(x);
    }
    inline ll sum(int x, int l, int r, int L, int R) {
        if(L <= l && r <= R) return s[x];
        down(x, l, r);
        int mid = l+r>>1;
        ll ret = 0;
        if(L <= mid) ret += sum(ls, l, mid, L, R);
        if(R > mid) ret += sum(rs, mid+1, r, L, R);
        return ret;
    }
    inline ll gmin(int x, int l, int r, int L, int R) {
        if(L <= l && r <= R) return mi[x];
        down(x, l, r);
        int mid = l+r>>1;
        ll ret = 1e18;
        if(L <= mid) ret = min(ret, gmin(ls, l, mid, L, R));
        if(R > mid) ret = min(ret, gmin(rs, mid+1, r, L, R));
        return ret;
    }
}T;

int main() {
    int Q, opt, l, r, x;
    cin >> n >> Q;
    for (int i=1; i<=n; ++i) scanf("%d", a+i);
    T.build(1, 1, n);
    while(Q--) {
         scanf("%d%d%d", &opt, &l, &r); ++l, ++r;
        if(opt == 1) {
            scanf("%d", &x);
            T.edt(1, 1, n, l, r, x);
        } else if(opt == 2) {
            scanf("%d", &x);
            T.div(1, 1, n, l, r, x);
        } else if(opt == 3) printf("%lld\n", T.gmin(1, 1, n, l, r));
        else printf("%lld\n", T.sum(1, 1, n, l, r));
    }
    return 0;
}

时间: 2024-10-13 17:09:06

loj6029 「雅礼集训 2017 Day1」市场的相关文章

【loj6029】「雅礼集训 2017 Day1」市场 线段树+均摊分析

题目描述 给出一个长度为 $n$ 的序列,支持 $m$ 次操作,操作有四种:区间加.区间下取整除.区间求最小值.区间求和. $n\le 100000$ ,每次加的数在 $[-10^4,10^4]$ 之间,每次除的数在 $[2,10^9]$ 之间. 题解 线段树+均摊分析 和 [uoj#228]基础数据结构练习题 类似的均摊分析题. 对于原来的两个数 $a$ 和 $b$ ( $a>b$ ) ,原来的差是 $a-b$ ,都除以 $d$ 后的差是 $\frac{a-b}d$ ,相当于差也除了 $d$

loj6045 「雅礼集训 2017 Day8」价

传送门:https://loj.ac/problem/6045 [题解] 由于存在完美匹配,所以选择k个药就要选择>=k个药材,我们要求的是选择k个药正好选择k个药材. 那么定义选一种减肥药的代价为-pi+INF,选一种药材的代价为INF,这样最小割肯定是恰好选k个 那么 最后答案就是最小割 - Σ(-pi+INF) [由于减肥药是负的所以要反过来...] 中间连的边要设成比inf大的.. # include <stdio.h> # include <string.h> #

「雅礼集训 2017 Day5」矩阵

填坑填坑.. 感谢wwt耐心讲解啊.. 如果要看这篇题解建议从上往下读不要跳哦.. 30pts 把$A$和$C$看成$n$个$n$维向量,那$A_i$是否加入到$C_j$中就可以用$B_{i,j}$表示了 枚举矩阵$A$,求出它的秩$r$,如果$C$在$A$的线性空间内则$C$可以被$A$表示出来 那么$B$矩阵的方案数就是$(2^{n-r})^n$ 这时候我们可以发现,由于枚举$A$覆盖了所有情况,秩相同的$C$的答案都是一样的 然后就可以打表算答案了.. 60pts 如果不想看可以跳过这段

LOJ #6035.「雅礼集训 2017 Day4」洗衣服 贪心

这道题的贪心好迷啊~我们对于两个过程进行单独贪心,然后再翻转一个,把这两个拼起来.先说一下单独贪心,单独贪心的话就是用一个堆,每次取出最小的,并且把这个最小的加上他单次的,再放进去.这样,我们得到的结果,是对于某些洗衣机,不停地洗,然后把这些洗衣机的时间,混在一起,排个序,由于对于每个洗衣机,如果被用到,那么他就会被不停地用,如果我们稍作改动,就一定会是用小的换来大的,所以这样最优.我们把两个拼起来为什么是对的呢.对于两个单独的答案,最优的无疑是,翻转之后拼起来,因为如果不是这样,也就是说进行了

#6030. 【雅礼集训 2017 Day1】矩阵

#6030. 「雅礼集训 2017 Day1」矩阵 题目描述 有一个 n×n  的矩阵,每个位置 (i,j) 如果是 . 表示为白色,如果是 # 表示为黑色. 初始时,每个位置可以是黑色或白色的,(i,j)  位置的值会作为 ai,j 给你. 现在有一种操作,选择两个整数 i,j∈[1,n],记 (i,1),(i,2),…,(i,n) (i, 1), (i, 2)的颜色为 C1,C2,…Cn ??,将 (1,j),(2,j),…,(n,j)  的颜色赋为 C1,C2,…,Cn ??. 你的任务是

「6月雅礼集训 2017 Day10」quote

[题目大意] 一个合法的引号序列是空串:如果引号序列合法,那么在两边加上同一个引号也合法:或是把两个合法的引号序列拼起来也是合法的. 求长度为$n$,字符集大小为$k$的合法引号序列的个数.多组数据. $1 \leq T \leq 10^5, 1 \leq n \leq 10^7, 1\leq K \leq 10^9$ [题解] 显然引号序列可以看做括号序列,于是我们有了一个$O(n^2)$的dp了. 设$f_{i,j}$表示到第$i$个位置,前面有$j$个左引号没有匹配,的方案数 每次,要么有

「6月雅礼集训 2017 Day7」电报

[题目大意] 有n个岛屿,第i个岛屿有有向发射站到第$p_i$个岛屿,改变到任意其他岛屿需要花费$c_i$的代价,求使得所有岛屿直接或间接联通的最小代价. $1 \leq n \leq 10^5, 1 \leq p_i,c_i \leq 10^9$ [题解] 显然最后是个大环,特判原来就是大环的情况. 考虑每个连通块最多保留多少. 树的答案可以直接dp做出来. 环的答案,根据树的答案dp出来. h[x][0/1]表示当前做到环上第i个点,环是否被切断了,的最大保留价值. 因为环必须被切断一次.所

「6月雅礼集训 2017 Day8」gcd

[题目大意] 定义times(a, b)表示用辗转相除计算a和b的最大公约数所需步骤. 那么有: 1. times(a, b) = times(b, a) 2. times(a, 0) = 0 3. times(a, b) = times(b, a mod b) + 1 对于$1 \leq x \leq A, 1 \leq y \leq B$,求times(A, B)的最大值,以及有多少对数取到了最大值. 多组数据. $T \leq 3 \times 10^5, 1 \leq A,B \leq

「6月雅礼集训 2017 Day7」三明治

[题目大意] $1 \leq n,m \leq 400$ N字形表示:上图第1行第1个那种:Z字形表示上图第1行第2个那种. [题解] 很容易得到结论: 考虑如果紫色比绿色先消去,那么黄色一定会比对应的白色先消去(这样才能消去白色). 然后我们可以知道,设取走$(x, y)$靠左的正方形,要$L(x,y)$步,那么$L(x,y) \geq L(x,y-1)$,同理也有$L(x, y) \geq L(x, y+1)$. 然后我们对于这个就可以进行一行一行的dfs了,dfs的时候可能会搜到原来已经搜