[HAOI2012]高速公路
设 \(A=\sum_{i=l}^{r}\sum_{j=i}^{r} dis_{i,j}\) , \(B= C_{r-l+1}^{2}\)
期望值为 \(\frac{A}{B}\)
我们发现这是一条链所以用一种常用的套路:边权化点权
然后发现这个\(dis_{i,j}\) 其实是 \(sum_j - sum_i\) 的
(\(sum_x=\sum_{i=1}^{x}a_i\))
考虑 \([L , R]\) 区间出现 \(a_i\) 的个数
我们可以发现其实是
\[\sum_{i=l}^{r} a_i * (r - i + 1) * (i - l + 1)
\]
\[= \sum_{i=l}^{r}a_i*((r*i-r*l+r)-(i^2-i*l+i)+i-l+1)
\]
\[=-\sum_{i=l}^{r}a_i*i^2+
(r-l+1-l*r)\sum_{i=l}^{r}a_i
+(l+r)\sum_{i=l}^{r}a_i*i\]
设\(s1 = \sum_{i=l}^{r}a_i,s2=\sum_{i=l}^{r}i*a_i,s3=\sum_{i=l}^{r}i^2*a_i\)
那么 \(ans =(l + r) * s2 + ((r - l) - l * r + 1) * s1 - s3\)
对于区间修改 懒标记以及修改方法
我们发现对 \(s1_{rt}\) 的影响是 \(\sum_{i=l}^{r} val\)
对 \(s2_{rt}\) 的影响是 \(\sum_{i=l}^{r}i*val\)
对 \(s3_{rt}\) 的影响是 \(\sum_{i=l}^{r}i^2*val\)
所以就维护一个静态的 \(s4_{rt} = \sum_{i=l}^{r}i\)
以及 \(s5_{rt} = \sum_{i=l}^{r}i^2\)
(\(\texttt{rt指的是某一段区间…学过线段树的都会(?)}\))
放上人傻常数大的代码
#include<bits/stdc++.h>
#define int long long
using namespace std ;
inline void read(int & x) {
register char c = x = 0 ; bool f = 0 ;
while(! isdigit(c)) { if(c == '-') f = 1 ; c = getchar() ; }
while(isdigit(c)) { x = (x << 1) + (x << 3) + (c & 15) ; c = getchar() ; }
if(f) x = -x ;
}
int n , m ;
const int N = 1e5 + 10 ;
int s1[N << 2] , s2[N << 2] , s3[N << 2] , s4[N << 2] , s5[N << 2] , tag[N << 2] ;
inline void pushup(int rt) { s1[rt] = s1[rt << 1] + s1[rt << 1 | 1] ;
s2[rt] = s2[rt << 1] + s2[rt << 1 | 1] ; s3[rt] = s3[rt << 1] + s3[rt << 1 | 1] ;
}
inline void build(int l , int r , int rt) {
if(l == r) { s4[rt] = l ; s5[rt] = l * l ; return ; }
int mid = l + r >> 1 ; build(l , mid , rt << 1) ; build(mid + 1 , r , rt << 1 | 1) ;
s4[rt] = s4[rt << 1] + s4[rt << 1 | 1] ; s5[rt] = s5[rt << 1] + s5[rt << 1 | 1] ;
}
inline void pushdown(int rt , int l , int r) {
if(! tag[rt]) return ; int mid = l + r >> 1 ;
tag[rt << 1] += tag[rt] ; tag[rt << 1 | 1] += tag[rt] ;
s1[rt << 1] += tag[rt] * (mid - l + 1) ; s1[rt << 1 | 1] += tag[rt] * (r - mid) ;
s2[rt << 1] += s4[rt << 1] * tag[rt] ; s2[rt << 1 | 1] += s4[rt << 1 | 1] * tag[rt] ;
s3[rt << 1] += s5[rt << 1] * tag[rt] ; s3[rt << 1 | 1] += s5[rt << 1 | 1] * tag[rt] ;
tag[rt] = 0 ;
}
inline void upd(int a , int b , int l , int r , int rt , int val) {
if(a <= l && r <= b) {
s1[rt] += val * (r - l + 1) ; s2[rt] += val * s4[rt] ;
s3[rt] += val * s5[rt] ; tag[rt] += val ;
return ;
} pushdown(rt , l , r) ;
int mid = l + r >> 1 ;
if(a <= mid) upd(a , b , l , mid , rt << 1 , val) ;
if(b > mid) upd(a , b , mid + 1 , r , rt << 1 | 1 , val) ;
pushup(rt) ;
}
inline void query(int a , int b , int l , int r , int rt , int & sum1 , int & sum2 , int & sum3) {
if(a <= l && r <= b) { sum1 += s1[rt] ; sum2 += s2[rt] ; sum3 += s3[rt] ; return ; }
pushdown(rt , l , r) ; int mid = l + r >> 1 ;
if(a <= mid) query(a , b , l , mid , rt << 1 , sum1 , sum2 , sum3) ;
if(b > mid) query(a , b , mid + 1 , r , rt << 1 | 1 , sum1 , sum2 , sum3) ;
}
signed main() {
#ifdef _WIN64
freopen("0.in" , "r" , stdin) ;
#endif
read(n) ; read(m) ;
build(1 , n , 1) ;
while(m --) {
char c = getchar() ;
while(isspace(c)) c = getchar() ;
if(c == 'C') {
int l , r , val ;
read(l) ; read(r) ; read(val) ;
upd(++ l , r , 1 , n , 1 , val) ;
} else {
int l , r ; read(l) ; read(r) ;
int sum1 , sum2 , sum3 ; sum1 = sum2 = sum3 = 0 ;
query(l + 1 , r , 1 , n , 1 , sum1 , sum2 , sum3) ;
int ans = (l + r + 1) * sum2 + ((r - l - 1) - (l + 1) * r + 1) * sum1 - sum3 ;
int down = (r - l + 1) * (r - l) >> 1 ;
int gcd = __gcd(ans , down) ;
cout << ans / gcd << '/' << down / gcd << '\n' ;
}
}
return 0 ;
}