码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 2752 [HAOI2012]高速公路(road) 线段树

时间:2018-08-14 20:04:24      阅读:124      评论:0      收藏:0      [点我收藏+]

标签:代码   namespace   php   www.   tchar   ble   for   while   return   

题面

题目传送门

解法

先把边转化成区间

其实我们只要计算\(\sum_{i=l}^{r-1}\sum_{j=i+1}^{r}sum(i,j)\)

把式子拆开,可以得到\((l+r)\sum w_i*i-(l+1)(r-1)\sum w_i-\sum w_i*i^2\)

用线段树分别维护这三个值即可

时间复杂度:\(O(m\ log\ n)\)

代码

#include <bits/stdc++.h>
#define int long long
#define N 100010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
    x = 0; int f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == ‘-‘) f = -1; c = getchar();}
    while (isdigit(c)) x = x * 10 + c - ‘0‘, c = getchar(); x *= f;
}
int s[N];
struct Info {int x, y, z;};
Info operator + (Info a, Info b) {return (Info) {a.x + b.x, a.y + b.y, a.z + b.z};}
struct SegmentTree {
    struct Node {
        int l, r, s1, s2, s3, del;
    } t[N * 4];
    void build(int k, int l, int r) {
        t[k] = (Node) {l, r, 0, 0, 0, 0};
        if (l == r) return; int mid = (l + r) >> 1;
        build(k << 1, l, mid); build(k << 1 | 1, mid + 1, r);
    }
    void Add(int k, int v) {
        int l = t[k].l, r = t[k].r;
        t[k].s1 += (r - l + 1) * v;
        t[k].s2 += (l + r) * (r - l + 1) / 2 * v;
        t[k].s3 += (s[r] - s[l - 1]) * v;
        t[k].del += v;
    }
    void update(int k) {
        t[k].s1 = t[k << 1].s1 + t[k << 1 | 1].s1;
        t[k].s2 = t[k << 1].s2 + t[k << 1 | 1].s2;
        t[k].s3 = t[k << 1].s3 + t[k << 1 | 1].s3;
    }
    void pushdown(int k) {
        int x = t[k].del; t[k].del = 0;
        Add(k << 1, x), Add(k << 1 | 1, x);
    }
    void modify(int k, int L, int R, int v) {
        int l = t[k].l, r = t[k].r;
        if (L <= l && r <= R) {Add(k, v); return;}
        if (t[k].del) pushdown(k);
        int mid = (l + r) >> 1;
        if (L <= mid && mid < R)
            modify(k << 1, L, mid, v), modify(k << 1 | 1, mid + 1, R, v);
        if (R <= mid) modify(k << 1, L, R, v);
        if (L > mid) modify(k << 1 | 1, L, R, v);
        update(k);
    }
    Info query(int k, int L, int R) {
        int l = t[k].l, r = t[k].r;
        if (L <= l && r <= R) return (Info) {t[k].s1, t[k].s2, t[k].s3};
        if (t[k].del) pushdown(k); int mid = (l + r) >> 1;
        if (R <= mid) return query(k << 1, L, R);
        if (L > mid) return query(k << 1 | 1, L, R);
        return query(k << 1, L, mid) + query(k << 1 | 1, mid + 1, R);
    }
} T;
int gcd(int x, int y) {
    if (y == 0) return x;
    return gcd(y, x % y);
}
main() {
    int n, m; read(n), read(m); T.build(1, 1, n - 1);
    for (int i = 1; i <= n; i++) s[i] = s[i - 1] + i * i;
    while (m--) {
        char c = getchar();
        while (!isalpha(c)) c = getchar();
        if (c == ‘C‘) {
            int l, r, v; read(l), read(r), read(v);
            T.modify(1, l, r - 1, v);
        } else {
            int l, r; read(l), read(r);
            Info tmp = T.query(1, l, r - 1);
            int x = -(l - 1) * r * tmp.x + (l + r - 1) * tmp.y - tmp.z, y = (r - l + 1) * (r - l) / 2;
            int t = gcd(x, y); cout << x / t << ‘/‘ << y / t << "\n";
        }
    }
    return 0;
}

bzoj 2752 [HAOI2012]高速公路(road) 线段树

标签:代码   namespace   php   www.   tchar   ble   for   while   return   

原文地址:https://www.cnblogs.com/copperoxide/p/9476718.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!