设 (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)
(( exttt{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 << '
' ;
}
}
return 0 ;
}