zoukankan      html  css  js  c++  java
  • bzoj 2752

    传送门: http://www.lydsy.com/JudgeOnline/problem.php?id=2752

    这道题其实想到线段树并不难,而且如果正确的推出了公式写起来也就是有点恶心而已= =实现不太容易出错。但是公式推起来确实比较的酸爽,加上我的公式又比较的迷,然后跑的飞慢= =

    这道题对于一个区间的期望,是整个区间的路径和除上区间的路径数目。数目可以O(1), 然后就在线段树中维护这个路径和。考虑区间合并(线段树都是这样= =),那么对于两个区间l, r, 那么路径和首先等于l的路径和加上r路径和,然后对于l中的一段路径,那么它的更新就是这条路径左边点的个数(包括左端点)* r中点的个数 * v,而出了r中的点的个数以外,其余部分作为一个元素up进行维护。 同样右边同理一个down 维护。 同时在更新这两个值的时候还需要维护一个区间和sum= =

    然后lazy 标记的下放:sum 直接搞,然后up 和down 都是 * len[区间长度]* (len - 1) * v; 

    ans += lazy * (1 * len * + 2 * (len - 1)  + 3 * (len - 3) ... + (len - 1) * 2 + len * 1) = len * (len + 1) * (len + 2) / 6 * lazy

    然后就搞搞= = 

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    typedef long long qword;
    const qword maxn = 101000;
    
    struct node {
        qword up, down, ans, lazy, sum;
        node *l, *r;
    }e[maxn * 3]; qword ne = 0;
    node* root;
    
    node* build(qword l, qword r) {
        node* now = e + ne ++;
        if(l ^ r) {
            qword mid = (l + r) >> 1;
            now-> l = build(l, mid);
            now-> r = build(mid + 1, r);
        }
        return now;
    }
    
    void update(node* x, qword l, qword r, qword mid) {
        if(l ^ r) {
            x-> ans = x-> l-> ans + x-> r-> ans + x-> l-> up * (r - mid) + x-> r-> down * (mid - l + 1);
            x-> sum = x-> l-> sum + x-> r-> sum;
            x-> up = x-> l-> up + x-> r-> up + x-> r-> sum * (mid - l + 1);
            x-> down = x-> l-> down + x-> r-> down + x-> l-> sum * (r - mid);
        }
    }
    
    void pushdown(node* x, qword l, qword r) {
        if(x-> l) {
            qword mid = (l + r) >> 1, v = x-> lazy, ln = mid - l + 1, rn = r - mid;
            x-> l-> ans += ln * (ln + 1) / 2 * (ln + 2) / 3 * v;
            x-> r-> ans += rn * (rn + 1) / 2 * (rn + 2) / 3 * v;
            x-> l-> sum += ln * v;
            x-> r-> sum += rn * v;
            x-> l-> up += ln * (ln + 1) / 2 * v;
            x-> r-> up += rn * (rn + 1) / 2 * v;
            x-> l-> down += ln * (ln + 1) / 2 * v;
            x-> r-> down += rn * (rn + 1) / 2 * v;
            x-> l-> lazy += v, x-> r-> lazy += v;
            x-> lazy = 0;
        }
    }
    
    void addlazy(node* now, qword l, qword r, qword ls, qword rs, qword v) {
        if(now-> lazy != 0) pushdown(now, l, r);
        if(l == ls && r == rs) {
            qword nn = rs - ls + 1; 
            now-> ans += nn * (nn + 1) / 2 * (nn + 2) / 3 * v;
            now-> sum += nn * v;
            now-> up += nn * (nn + 1) / 2 * v;
            now-> down += nn * (nn + 1) / 2 * v;
            now-> lazy += v;
        }
        else {
            qword mid = (l + r) >> 1;
            if(rs <= mid) addlazy(now-> l, l, mid, ls, rs, v);
            else if(ls > mid) addlazy(now-> r, mid + 1, r, ls, rs, v);
            else addlazy(now-> l, l, mid, ls, mid, v), addlazy(now-> r, mid + 1, r, mid + 1, rs, v);
            update(now, l, r, mid);
        }
    }
    
    node ask(node* now, qword l, qword r, qword ls, qword rs) {
        if(now-> lazy != 0) pushdown(now, l, r);
        node ret;
        if(l == ls && r == rs) ret = *now;
        else {
            qword mid = (l + r) >> 1;
            if(rs <= mid) ret = ask(now-> l, l, mid, ls, rs);
            else if(ls > mid) ret = ask(now-> r, mid + 1, r, ls, rs);
            else {
                node lr = ask(now-> l, l, mid, ls, mid);
                node rr = ask(now-> r, mid + 1, r, mid + 1, rs);
                ret.l = &lr, ret.r = &rr;
                update(&ret, ls, rs, mid);
            }
        }
        return ret;
    }
    
    qword qword_get() {
        qword x = 0; char c = (char)getchar();
        qword f = 0;
        while(!isdigit(c) && c != '-') c = (char)getchar();
        if(c == '-') c =(char)getchar(), f = 1;
        while(isdigit(c)) {
            x = x * 10 + (qword)(c - '0');
            c = (char)getchar();
        }
        if(f) x = -x;
        return x;
    }
    
    qword n, m;
    
    qword gcd(qword a, qword b) {
        return a % b == 0 ? b : gcd(b, a % b);
    }
    
    void test(node* now, qword l, qword r) {
        cout << l <<" "<< r <<" "<< now-> ans <<" "<< now-> sum <<" " << now-> up <<" "<< now-> down <<" "<< now-> lazy << endl;
        if(l ^ r) {
            qword mid = (l + r) >> 1;
            test(now-> l, l, mid), test(now-> r, mid + 1, r);
        }
    }
    
    void sov() {
        n = qword_get(), m = qword_get();
        root = build(1, n - 1);
        char s[10]; 
        while(m --) {
            scanf("%s", s + 1);
            if(s[1] =='C') {
                qword ls, rs, v; 
                ls = qword_get(); rs = qword_get(); v = qword_get();
                rs --;
                addlazy(root, 1, n - 1, ls, rs, v);
            }
            if(s[1] == 'Q') {
                qword ls, rs; 
                ls = qword_get(), rs = qword_get();
                rs --;
                node ret = ask(root, 1, n - 1, ls, rs);
                qword a = ret.ans;
                qword b = (rs - ls + 1) * (rs - ls + 2) / 2;
                qword g = gcd(a, b);
                printf("%lld/%lld
    ", a / g, b / g);
            }
        }
    }
    
    int main() {
        //freopen("test.in", "r", stdin);
        //freopen("test.out", "w", stdout);
        sov();
        return 0;
    } 
  • 相关阅读:
    函数对象、名称空间与作用域
    函数
    leetcode语法练习(二)
    leetcode语法练习(一)
    字符编码与文件操作
    集合类型内置方法与总结
    列表,元组与字典类型
    数据类型内置方法之数据类型与字符串类型
    [SVG实战]饼图全面解析
    [JavaScript语法学习]重新认识JavaScript
  • 原文地址:https://www.cnblogs.com/ianaesthetic/p/4148260.html
Copyright © 2011-2022 走看看