Luogu 4433 [COCI2009-2010#1] ALADIN

LOJ 2958

线段树 + 类欧

主要矛盾就是$\sum\limits_{i = l}^{r}Ai \mod B$怎么做。

拆成前缀和相减的形式,有

$$\sum_{i = 0}^{r}(Ai \mod B) - \sum_{i = 0}^{l - 1}(Ai \mod B)$$

我们知道

$$a \mod b = a - \left \lfloor \frac{a}{b} \right \rfloor b$$

那么

$$\sum_{i = 0}^{n}Ai \mod B = \sum_{i = 0}^{n} Ai - \left \lfloor \frac{Ai}{B} \right \rfloor B = \frac{An(n + 1)}{2} - B\sum_{i = 0}^{n}\left \lfloor \frac{Ai}{B} \right \rfloor$$

后面那个东西就是类欧模板中的$f(A, 0, B, n)$。

还有一件事情:$10^9 * 2 * 10^9 / 2 * 10^6 = 10^{24} > long\ long$,所以我写了一个$\text{__int128}$。

因为标记一定要下传,所以似乎不能动态开点而需要离散,但是离散之后注意到线段树一个结点左右儿子可能并不是连续的。

举个栗子,假如我们离散完之后的序列是${1, 5, 7, 9}$,那么一号结点对应的区间是$[1, 9]$,而它的左儿子是$[1, 5]$,右儿子是$[7, 9]$,中间还有一段$[6, 6]$的空缺。所以我们在$up$和算答案的时候需要考虑这段空缺的贡献(可能是我线段树没学好qwq)。

这样子的话效率就很迷人了。

时间复杂度$O(qlog^2n)$。

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef __int128 ILL;

const int N = 1e5 + 5;

int n, qn, tot = 0, buc[N];

struct Options {
    int op, l, r, A, B;
} q[N];

namespace Fread {
    const int L = 1 << 15;
    
    char buffer[L], *S, *T;
    
    inline char Getchar() {
        if(S == T) {
            T = (S = buffer) + fread(buffer, 1, L, stdin);
            if(S == T) return EOF;
        }
        return *S++;
    }
    
    template <class T> 
    inline void read(T &X) {
        char ch; T op = 1;
        for(ch = Getchar(); ch > '9' || ch < '0'; ch = Getchar())
            if(ch == '-') op = -1;
        for(X = 0; ch >= '0' && ch <= '9'; ch = Getchar()) 
            X = (X << 1) + (X << 3) + ch - '0'; 
        X *= op;
    }
    
} using namespace Fread;   

namespace Fwrite {
    const int L = 1 << 15;
    
    char buf[L], *pp = buf;
    
    void Putchar(const char c) {
        if(pp - buf == L) fwrite(buf, 1, L, stdout), pp = buf;
        *pp++ = c;
    }
    
    template<typename T>
    void print(T x) {
        if(x < 0) {
            Putchar('-');
            x = -x;
        }
        if(x > 9) print(x / 10);
        Putchar(x % 10 + '0');
    }
    
    void fsh() {
        fwrite(buf, 1, pp - buf, stdout);
        pp = buf;
    }
    
    template <typename T>
    inline void write(T x, char ch = 0) {
        print(x);
        if (ch != 0) Putchar(ch);
        fsh();
    }

} using namespace Fwrite;

namespace LikeGcd {
    ILL solve(ILL a, ILL b, ILL c, ILL n) {
        if (!a) return (b / c) * (n + 1);
        if (a >= c || b >= c) 
            return (a / c) * n * (n + 1) / 2 + (b / c) * (n + 1) + solve(a % c, b % c, c, n);
        if (a < c && b < c) {
            ILL m = (a * n + b) / c;
            return n * m - solve(c, c - b - 1, a, m - 1);
        }
        return 0;
    }    
}

namespace SegT {
    struct Node {
        int st, A, B;
        ll sum;
        bool tag;
    } s[N << 2];
    
    #define lc p << 1
    #define rc p << 1 | 1
    #define mid ((l + r) >> 1)
    #define st(p) s[p].st
    #define A(p) s[p].A
    #define B(p) s[p].B
    #define sum(p) s[p].sum
    #define tag(p) s[p].tag
    
    inline ll calc(int p, int st, int en) {
//        int st = st(p), en = st(p) + buc[r] - buc[l];
        if (!B(p)) return 0;
        ILL res = 0;
        res += (ILL)A(p) * (ILL)(st + en) * (ILL)(en - st + 1) / (ILL)2;
        res -= (ILL)B(p) * (LikeGcd :: solve(A(p), 0, B(p), en) - LikeGcd :: solve(A(p), 0, B(p), st - 1));
        return 1LL * res;
    }
    
    inline void up(int p, int l, int r) {
        sum(p) = sum(lc) + sum(rc);
        if (buc[mid] + 1 != buc[mid + 1]) {
            sum(p) += calc(p, st(p) + buc[mid] + 1 - buc[l], st(p) + buc[mid + 1] - 1 - buc[l]);
        }
    }
    
    inline void down(int p, int l, int r) {
        if (!tag(p)) return;
        st(lc) = st(p), st(rc) = st(p) + buc[mid + 1] - buc[l];
        A(lc) = A(rc) = A(p);
        B(lc) = B(rc) = B(p);
        tag(lc) = tag(rc) = 1;
        sum(lc) = calc(lc, st(lc), st(lc) + buc[mid] - buc[l]);
        sum(rc) = calc(rc, st(rc), st(rc) + buc[r] - buc[mid + 1]);
        tag(p) = 0;
    }
    
    void modify(int p, int l, int r, int x, int y, int A, int B) {
        if (x <= l && y >= r) {
            tag(p) = 1;
            st(p) = buc[l] - buc[x] + 1, A(p) = A, B(p) = B;
            sum(p) = calc(p, st(p), st(p) + buc[r] - buc[l]);
            return;
        }
        
        down(p, l, r);
        
        if (x <= mid) modify(lc, l, mid, x, y, A, B);
        if (y > mid) modify(rc, mid + 1, r, x, y, A, B);
        if (buc[mid + 1] != buc[mid] + 1) {
            if (buc[x] <= buc[mid] + 1 && buc[y] >= buc[mid + 1] - 1) {
                A(p) = A, B(p) = B;
                st(p) = buc[l] - buc[x] + 1;
            }
        }
        
        up(p, l, r);
    }
    
    ll query(int p, int l, int r, int x, int y) {
        if (x <= l && y >= r) return sum(p);
        down(p, l, r);
        
        ll res = 0;
        if (x <= mid) res += query(lc, l, mid, x, y);
        if (y > mid) res += query(rc, mid + 1, r, x, y);
        if (buc[mid + 1] != buc[mid] + 1) {
            if (buc[y] >= buc[mid] + 1 && buc[x] <= buc[mid + 1] - 1) {
                int ln = max(buc[mid] + 1, buc[x]);
                int rn = min(buc[mid + 1] - 1, buc[y]);
                res += calc(p, st(p) + ln - buc[l], st(p) + rn - buc[l]);            
            } 
        }
        
        return res;
    }
    
    void ddd(int p, int l, int r) {
        if (l == r) return;
        down(p, l, r);
        ddd(lc, l, mid), ddd(rc, mid + 1, r);
    }
    
} using namespace SegT;

int main() {
/*    #ifndef ONLINE_JUDGE
        freopen("input.txt", "r", stdin);
    #endif      */
    
    read(n), read(qn);
    for (int i = 1; i <= qn; i++) {
        read(q[i].op), read(q[i].l), read(q[i].r);
        buc[++tot] = q[i].l, buc[++tot] = q[i].r;
        if (q[i].op == 1) read(q[i].A), read(q[i].B);
    }
    
    sort(buc + 1, buc + 1 + tot);
    tot = unique(buc + 1, buc + 1 + tot) - buc - 1;
    
//    for (int i = 1; i <= tot; i++)
//        printf("%d%c", buc[i], " \n"[i == tot]);     
    
    for (int i = 1; i <= qn; i++) {
        q[i].l = lower_bound(buc + 1, buc + 1 + tot, q[i].l) - buc;
        q[i].r = lower_bound(buc + 1, buc + 1 + tot, q[i].r) - buc;
    }
    
    for (int i = 1; i <= qn; i++) {
        if (q[i].op == 1) modify(1, 1, tot, q[i].l, q[i].r, q[i].A, q[i].B);
        else write(query(1, 1, tot, q[i].l, q[i].r), '\n');
        
/*        ddd(1, 1, tot);
        printf("\n");
        for (int j = 1; j <= 9; j++) 
            printf("%d %lld %d %d %d\n", j, sum(j), A(j), B(j), st(j));    */
    }
    
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/CzxingcHen/p/10388319.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值