zoukankan      html  css  js  c++  java
  • HAOI2012 高速公路

    题目传送门

    不开long long见祖宗系列


    很自然的想法是求出所有区间的价值然后除区间个数

    怎么求区间价值?
    设数(x)的位置为(p),则(x)([l,r])中所有区间的价值做出了((r−p+1) imes (p−l+1))次贡献(乘法原理)
    将这个式子拆开,就是((r−l+1−r imes l) imes x imes p^2+(r+l) imes x imes p − x)

    然后用线段树维护一下(x imes p ^ 2 , x imes p)(x)就可以了

    最后将这个值除以区间个数就好了

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define LL long long
    #define ls p << 1
    #define rs p << 1 | 1
    #define mid ((l + r) >> 1)
    using namespace std;
    LL read() {
        LL k = 0, f = 1; char c = getchar();
        while(c < '0' || c > '9') {
            if(c == '-') f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9')
            k = k * 10 + c -48, c = getchar();
        return k * f;
    }
    char read_c() {
        char c = getchar();
        while(c != 'C' && c != 'Q') c = getchar();
        return c;
    }
    LL calc(bool opt, LL l, LL r) {
        if(opt) // 维护 x*p
            return (l+r) * (r-l+1) / 2;
        else {
            l -= 1; // 维护 x*p*p
            return (r * (r+1) * ((r<<1)+1) / 6) - (l * (l+1) * ((l<<1)+1) / 6);
        }
    }
    struct zzz {
        LL s1, s2, s3;
        void operator += (const zzz &y) & { //重载运算符,可以直接用 += 相加
            s1 += y.s1, s2 += y.s2, s3 += y.s3;
            return ;
        }
    }tree[100010 << 2];
    LL tag[100010 << 2];
    void up(LL p) {
        tree[p].s1 = tree[ls].s1 + tree[rs].s1;
        tree[p].s2 = tree[ls].s2 + tree[rs].s2;
        tree[p].s3 = tree[ls].s3 + tree[rs].s3;
    }
    void down(LL p, LL l, LL r) {
        LL k = tag[p];
        tree[ls].s1 += (mid-l+1) * k;
        tree[ls].s2 += calc(1, l, mid) * k;
        tree[ls].s3 += calc(0, l, mid) * k;
    
        tree[rs].s1 += (r-mid) * k;
        tree[rs].s2 += calc(1, mid+1, r) * k;
        tree[rs].s3 += calc(0, mid+1, r) * k;
    
        tag[ls] += k; tag[rs] += k; tag[p] = 0;
    }
    void update(LL l, LL r, LL p, LL nl, LL nr, LL k) {
        if(nl <= l && nr >= r) {
            tree[p].s1 += (r-l+1) * k;
            tree[p].s2 += calc(1, l, r) * k;
            tree[p].s3 += calc(0, l, r) * k;
            tag[p] += k; return ;
        }
        down(p, l, r);
        if(nl <= mid) update(l, mid, ls, nl, nr, k);
        if(nr > mid) update(mid+1, r, rs, nl, nr, k);
        up(p);
    }
    zzz query(LL l, LL r, LL p, LL nl, LL nr) {
        zzz ans = (zzz){0, 0, 0};
        if(nl <= l && nr >= r)
            return tree[p];
        down(p, l, r);
        if(nl <= mid)
            ans += query(l, mid, ls, nl, nr);
        if(nr > mid)
            ans += query(mid+1, r, rs, nl, nr);
        up(p);
        return ans;
    }
    LL gcd(LL x, LL y) {
        return x % y == 0 ? y : gcd(y, x % y);
    }
    int main() {
        LL n = read(), m = read();
        for(LL i = 1; i <= m; ++i) {
            char opt = read_c(); LL l = read(), r = read() - 1;
            if(opt == 'C') {
                LL k = read();
                update(1, n, 1, l, r, k);
            }
            else {
                zzz x = query(1, n, 1, l, r);
                LL ans = (r-l+1-r*l) * x.s1 + (r+l) * x.s2 - x.s3;
                LL b = (r-l+2) * (r-l+1) / 2;
                LL g = gcd(ans, b); //约分
                printf("%lld/%lld
    ", ans/g, b/g);
            }
        }
    
        return 0;
    }
    
  • 相关阅读:
    gc buffer busy/gcs log flush sync与log file sync
    给Oracle年轻的初学者的几点建议
    Android 编程下帧动画在 Activity 启动时自动运行的几种方式
    Android 编程下 Touch 事件的分发和消费机制
    Java 编程下 static 关键字
    Java 编程下 final 关键字
    Android 编程下模拟 HOME 键效果
    Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated ?
    Extjs4 大型项目目录结构重构
    [转]SQLServer 2008 允许远程连接的配置方法
  • 原文地址:https://www.cnblogs.com/morslin/p/11855243.html
Copyright © 2011-2022 走看看