zoukankan      html  css  js  c++  java
  • Luogu 4433 [COCI2009-2010#1] ALADIN

    LOJ 2958

    线段树 + 类欧

    主要矛盾就是$sumlimits_{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} ight floor b$$

    那么

    $$sum_{i = 0}^{n}Ai mod B = sum_{i = 0}^{n} Ai - left lfloor frac{Ai}{B} ight floor B = frac{An(n + 1)}{2} - Bsum_{i = 0}^{n}left lfloor frac{Ai}{B} ight floor$$

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

    还有一件事情:$10^9 * 2 * 10^9 / 2 * 10^6 = 10^{24} > long long$,所以我写了一个$ ext{__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], " 
    "[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), '
    ');
            
    /*        ddd(1, 1, tot);
            printf("
    ");
            for (int j = 1; j <= 9; j++) 
                printf("%d %lld %d %d %d
    ", j, sum(j), A(j), B(j), st(j));    */
        }
        
        return 0;
    }
    View Code
  • 相关阅读:
    系统综合实践 第1次实践作业
    Linq 中按照多个值进行分组(GroupBy,Count)
    敏捷开发综述
    心率
    二维数组 子数组和的最大值
    电梯调度算法
    课堂测试用例。。。
    分析文本文件中各单词出现的频率,并把频率最高的十个词打印出来
    dwz tree组件 取得所选择的值
    SQL Server -- 已成功与服务器建立连接,但是在登录过程中发生错误
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/10388319.html
Copyright © 2011-2022 走看看