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;
}
原文地址:https://www.cnblogs.com/morslin/p/11855243.html