1. 程式人生 > >和Leo一起做愛線段樹/數學的好孩子之[HAOI2012]高速公路

和Leo一起做愛線段樹/數學的好孩子之[HAOI2012]高速公路

Y901高速公路是一條重要的交通紐帶,政府部門建設初期的投入以及使用期間的養護費用都不低,因此政府在這條高速公路上設立了許多收費站。

Y901高速公路是一條由N-1段路以及N個收費站組成的東西向的鏈,我們按照由西向東的順序將收費站依次編號為1~N,從收費站i行駛到i+1(或從i+1行駛到i)需要收取Vi的費用。高速路剛建成時所有的路段都是免費的。

政府部門根據實際情況,會不定期地對連續路段的收費標準進行調整,根據政策漲價或降價。

無聊的小A同學總喜歡研究一些稀奇古怪的問題,他開車在這條高速路上行駛時想到了這樣一個問題:對於給定的l,r(l< r),在第l個到第r個收費站裡等概率隨機取出兩個不同的收費站a和b,那麼從a行駛到b將期望花費多少費用呢?

自從上次在樹上搞了這個操作之後
我覺得不是特別難了
我們思考暴力這個期望:
E = i = l

r j = l + 1
r
D i s ( i , j ) C r l + 1 2 E=\frac{\sum_{i=l}^{r}\sum_{j=l+1}^{r}Dis(i,j)}{C_{r-l+1}^{2}}
我們拆開這個式子
發現貢獻是:
i = l r W i ( r i + 1 ) ( l i + 1 ) \sum_{i=l}^{r}W_{i}(r-i+1)(l-i+1)
暴力拆開:
( r l + 1 r l ) W i + ( r + l ) W i i W i i i (r-l+1-r*l)*W_{i}+(r+l)*W_{i}*i-W_{i}*i*i
實際上就是維護個區間求和
線段樹維護就好了
那麼區間加就可以維護了:
維護:
i \sum i i 2 \sum i^{2}
完。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define int long long 
#define lc (p<<1)
#define rc (p<<1|1)
const int N=1e5+1000;
inline void read(int &x){
    x=0;
    int f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    x*=f;
}
int a[N];
int GetGCD(int x,int y){
    while(y){
        int tmp=y;
        y=x%y;
        x=tmp;
    }
    return x;
}	
struct Node{
    int lson,rson;
    int sum1;//a[i]
    int sum2;//a[i]*i
    int sum3;//a[i]*i*i
    int sum4;//i
    int sum5;//i*i
    int lazy;
    Node(){
        lson=rson=sum1=sum2=sum3=sum4=sum5=lazy=0;
    }
}T[N<<2];
Node operator + (Node A,Node B){
    Node C;
    C.sum1=A.sum1+B.sum1;
    C.sum2=A.sum2+B.sum2;
    C.sum3=A.sum3+B.sum3;
    C.sum4=A.sum4+B.sum4;
    C.sum5=A.sum5+B.sum5;	
    C.lson=A.lson;
    C.rson=B.rson;
    return C;	
}
struct Segment_Tree{
    inline void PushNow(int p,int val){
            T[p].sum1+=(T[p].rson-T[p].lson+1)*val;
            T[p].sum2+=T[p].sum4*val;
            T[p].sum3+=T[p].sum5*val;
            T[p].lazy+=val;		
    }
    inline void PushDown(int p){
        if(T[p].lazy){
            PushNow(lc,T[p].lazy);
            PushNow(rc,T[p].lazy);
            T[p].lazy=0;
        }
    }
    inline void Build(int p,int l,int r){
        T[p].lson=l;
        T[p].rson=r;
        if(l==r){
            T[p].sum1=a[l];
            T[p].sum2=a[l]*l;
            T[p].sum3=a[l]*l*l;
            T[p].sum4=l;
            T[p].sum5=l*l;
            return;
        }
        int mid=(l+r)>>1;
        Build(lc,l,mid);
        Build(rc,mid+1,r);
        T[p]=T[lc]+T[rc];
    }
    inline void Update(int p,int l,int r,int val){
        if(l<=T[p].lson&&T[p].rson<=r){
            PushNow(p,val);
            return;
        }
        int mid=(T[p].lson+T[p].rson)>>1;
        PushDown(p);
        if(l<=mid)Update(lc,l,r,val);
        if(mid< r)Update(rc,l,r,val);
        T[p]=T[lc]+T[rc];
    }
    Node Query(int p,int l,int r){
        if(l<=T[p].lson&&T[p].rson<=r){
            return T[p];
        }
        int mid=(T[p].lson+T[p].rson)>>1;
        PushDown(p);
        Node ret;
        if(l<=mid)ret=ret+Query(lc,l,r);
        if(mid <r)ret=ret+Query(rc,l,r);
        return ret;
    }
}Tree;
int n,Q;
char S[10];
signed main(){
// 	freopen("test.in","r",stdin);
    read(n);
    read(Q);
    Tree.Build(1,1,n);
    while(Q--){
        scanf("%s",S+1);
        if(S[1]=='C'){
            int l,r,v;
            read(l);
            read(r);
            r--;
            read(v);
            Tree.Update(1,l,r,v);
        }
        else{
            int l,r;
            read(l);
            read(r);
            r--;
            Node Now=Tree.Query(1,l,r);
            int son=(r-l+1-r*l)*Now.sum1+(r+l)*Now.sum2-Now.sum3;
//			cout<<Now.sum1<<" "<<Now.sum2<<" "<<Now.sum3<<'\n';
            int mother=(r-l+2)*(r-l+1)/2;
            int GCD=GetGCD(son,mother);
            cout<<son/GCD<<"/"<<mother/GCD<<'\n';
        }
    }
}