首先便于计算,我们可以将每一条边缩成一个点,于是右端点\(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; }