[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 ;
}
posted @ 2019-11-14 18:11  _Isaunoya  阅读(142)  评论(0编辑  收藏  举报