luoguP2221 [HAOI2012]高速公路

首先便于计算,我们可以将每一条边缩成一个点,于是右端点\(r\)需要减\(1\).
\(a\)行驶到\(b\)将期望花费
\[ \begin{align} ans=\dfrac{Ans}{C^{2}_{r-l+2}} \end{align} \]
我们可以对于每一条边统计它被算了多少次.
\[ \begin{align} \therefore Ans&=\sum^r_{i=l}v[i]*(i-l+1)(r-i+1)\\ &=\sum^r_{i=l}v[i]*[-i^2+(l+r)*i+(1+r)(1-l)]\\ &=-\sum^r_{i=l}v[i]*i^2+(l+r)\sum^r_{i=l}v[i]*i-(r+1)(l-1)\sum^r_{i=l}v[i] \end{align} \]
于是我们只需要在线段树中维护三个值.
\[ \begin{align} tr[0][x]&=\sum^{x.r}_{i=x.l}a[i]\\ tr[1][x]&=\sum^{x.r}_{i=x.l}a[i]*i\\ tr[2][x]&=\sum^{x.r}_{i=x.l}a[i]*i^2\\ \end{align} \]
合并非常简单.
\[ \begin{align} tr[0][x]&=tr[0][x<<1]+tr[0][x<<1|1]\\ tr[1][x]&=tr[1][x<<1]+tr[1][x<<1|1]\\ tr[2][x]&=tr[2][x<<1]+tr[2][x<<1|1]\\ \end{align} \]
但是如何修改呢?

对于\(tr[0]\):
\[ \begin{align} \Delta tr[0][x]&=\sum^{x.r}_{i=x.l}\Delta v[i]\\ &=k\sum^{x.r}_{i=x.l}1\\ &=k*(x.r-x.l+1) \end{align} \]
对于\(tr[1]\):
\[ \begin{align} \Delta tr[1][x]&=\sum^{x.r}_{i=x.l}\Delta v[i]*i\\ &=k\sum^{x.r}_{i=x.l}i\\ &=k*(x.r+x.l)*(x.r-x.l+1)/2 \end{align} \]
对于\(tr[2]\):
\[ \begin{align} \Delta tr[2][x]&=\sum^{x.r}_{i=x.l}\Delta v[i]*i^2\\ &=k\sum^{x.r}_{i=x.l}i^2\\ &=k(\sum^{x.r}_{i=1}i^2-\sum^{x.l-1}_{i=1}i^2) \end{align} \]
相信大家都学过平方相加的公式:
\[ \begin{align} 1^2+2^2+......+n^2=\frac{n(n+1)(2n+1)}{6} \end{align} \]
没学过的可以康康
\[ \begin{align} \therefore\Delta tr[2][x]&=\frac{x.r(x.r+1)(2x.r+1)-(x.l-1)x.l(2x.l-1)}{6} \end{align} \]
最后:
一定要开longlong​!

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define il inline
#define rg register
#define gi read<int>
using namespace std;
typedef long long ll;
const int O = 1e5 + 10;
template<class TT>
il TT read() {
    TT o = 0,fl = 1; char ch = getchar();
    while (!isdigit(ch) && ch != '-') ch = getchar();
    if (ch == '-') fl = -1, ch = getchar();
    while (isdigit(ch)) o = o * 10 + ch - '0', ch = getchar();
    return fl * o;
}
char ch[2];
int n, m;
ll xx, yy, zz;
class SegmentTree {
private:
    ll tr[6][O << 2], lazy[O << 2];
    il void pushup(int x) {
        tr[0][x] = tr[0][x << 1] + tr[0][x << 1 | 1];
        tr[1][x] = tr[1][x << 1] + tr[1][x << 1 | 1];
        tr[2][x] = tr[2][x << 1] + tr[2][x << 1 | 1];
    }
    il void work(int delta, int x, int len) {
        tr[0][x] += 1ll * delta * len;
        tr[1][x] += 1ll * delta * tr[4][x];
        tr[2][x] += 1ll * delta * tr[5][x];
        lazy[x] += delta;
    }
    il void pushdown(int x, int l, int r) {
        if(!lazy[x]) return ;
        int mid = l + r >> 1;
        work(lazy[x], x << 1, mid - l + 1);
        work(lazy[x], x << 1 | 1, r - mid);
        lazy[x] = 0;
    }
public:
    il void Build(int x, int l, int r) {
        if (l == r) {
            tr[4][x] = l;
            tr[5][x] = 1ll * l * l;
            return ;
        }
        int mid = l + r >> 1;
        Build(x << 1, l, mid);
        Build(x << 1 | 1, mid + 1, r);
        tr[4][x] = tr[4][x << 1] + tr[4][x << 1 | 1];
        tr[5][x] = tr[5][x << 1] + tr[5][x << 1 | 1];
    }
    il void Modify(int x, int l, int r, int L, int R, int delta) {
        if (l > R || L > r) return ;
        if (L <= l && r <= R) return work(delta, x, r - l + 1);
        pushdown(x, l, r);
        int mid = l + r >> 1;
        Modify(x << 1, l, mid, L, R, delta);
        Modify(x << 1 | 1, mid + 1, r, L, R, delta);
        pushup(x);
    }
    il void Query(int x, int l, int r, int L, int R) {
        if (l > R || L > r) return ;
        if (L <= l && r <= R) {
            xx += tr[0][x];
            yy += tr[1][x];
            zz += tr[2][x];
            return ;
        }
        pushdown(x, l, r);
        int mid = l + r >> 1;
        Query(x << 1, l, mid, L, R);
        Query(x << 1 | 1, mid + 1, r, L, R);
    }
}st;
int main() {
    n = gi(), m = gi();
    st.Build(1, 1, n);
    while (m--) {
        scanf("%s", ch);
        int l = gi(), r = gi() - 1;
        if (ch[0] == 'C') st.Modify(1, 1, n, l, r, gi());
        else {
            xx = yy = zz = 0;
            st.Query(1, 1, n, l, r);
            ll X = 1ll * (l + r) * yy + 1ll * (r + 1) * (1 - l) * xx - zz;
            ll Y = 1ll * (r - l + 2) * (r - l + 1) >> 1, g = __gcd(X, Y);
            X /= g, Y /= g;
            printf("%lld/%lld\n", X, Y);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lylyl/p/11694667.html