和Leo一起做爱线段树/数学的好孩子之[HAOI2012]高速公路

版权声明:LeoJAM Presents https://blog.csdn.net/fcb_x/article/details/83154371

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';
        }
    }
}

猜你喜欢

转载自blog.csdn.net/fcb_x/article/details/83154371