[HAOI2012]高速公路

题意

给你一个序列 , , 询问一个区间求从中任选一个子区间的权值和的期望,带修改


题解

sum(L,R)=Ri=Lwi, s u m ( L , R ) = ∑ i = L R w i , 可以想到

E=i=LRj=iRsum(i,j)(RL+12) E = ∑ i = L R ∑ j = i R s u m ( i , j ) ( R − L + 1 2 )

即所有情况的和除以每种情况的概率

考虑怎么求 Ri=LRj=isum(i,j) ∑ i = L R ∑ j = i R s u m ( i , j )

考虑到每一个 wi w i 会存在于 (iL+1)×(Ri+1) ( i − L + 1 ) × ( R − i + 1 ) 个区间中 ( ( 分别枚举左右端点)

可以得到

i=LRj=iRsum(i,j)=i=LRwi(iL+1)×(Ri+1) ∑ i = L R ∑ j = i R s u m ( i , j ) = ∑ i = L R w i ( i − L + 1 ) × ( R − i + 1 )

化简得

(R+1)(1L)wi+(L+R)wiiwii2 ( R + 1 ) ( 1 − L ) ∑ w i + ( L + R ) ∑ w i i − ∑ w i i 2

其中那三样东西都可以用线段树维护

特殊的 ni=1i2=(2n+1)n(n+1)6 ∑ i = 1 n i 2 = ( 2 n + 1 ) n ( n + 1 ) 6

注意这题中的一些细节

把边权化为点权时如果直接 R − − R 的话那么分母应该是 (RL+22) ( R − L + 2 2 )

#include<bits/stdc++.h>
#define fp(i,a,b) for(register int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(register int i=a,I=b-1;i>I;--i)
#define go(u) for(register int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
char ss[1<<17],*A=ss,*B=ss;
inline char gc(){return A==B&&(B=(A=ss)+fread(ss,1,1<<17,stdin),A==B)?-1:*A++;}
template<class T>inline void sd(T&x){
    char c;T y=1;while(c=gc(),(c<48||57<c)&&c!=-1)if(c==45)y=-1;x=c-48;
    while(c=gc(),47<c&&c<58)x=x*10+c-48;x*=y;
}
char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
template<class T>inline void we(T x){
    if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+5;
typedef int arr[N];
typedef long long ll;
int n,m,tg[N<<2];ll tr[N<<2][3];
#define lc p<<1
#define rc p<<1|1
inline ll calc(int x){return (ll)(x<<1|1)*x*(x+1)/6;}
inline void Tag(int p,int L,int R,int w){
    int x=(R-L+1);tg[p]+=w;
    tr[p][0]+=(ll)w*x;
    tr[p][1]+=(ll)w*x*(L+R)>>1;
    tr[p][2]+=(calc(R)-calc(L-1))*w;
}
inline void down(int p,int L,int R){
    int mid=(L+R)>>1,w=tg[p];tg[p]=0;
    Tag(lc,L,mid,w),Tag(rc,mid+1,R,w);
}
inline void up(int p){fp(i,0,2)tr[p][i]=tr[lc][i]+tr[rc][i];}
void mdy(int p,int L,int R,int a,int b,int w){
    if(a<=L&&R<=b)return Tag(p,L,R,w);
    if(tg[p])down(p,L,R);int mid=(L+R)>>1;
    if(a<=mid)mdy(lc,L,mid,a,b,w);
    if(b>mid)mdy(rc,mid+1,R,a,b,w);up(p);
}
ll qry(int p,int L,int R,int a,int b,int y){
    if(a<=L&&R<=b)return tr[p][y];
    if(tg[p])down(p,L,R);int mid=(L+R)>>1;
    if(b<=mid)return qry(lc,L,mid,a,b,y);
    if(a>mid)return qry(rc,mid+1,R,a,b,y);
    return qry(lc,L,mid,a,b,y)+qry(rc,mid+1,R,a,b,y);
}
int main(){
    #ifndef ONLINE_JUDGE
        file("roadxw");
    #endif
    sd(n),sd(m);--n;
    int L,R;char c;ll x,y,g;
    while(m--){
        while(c=gc(),c<32);sd(L),sd(R);--R;
        if(c=='C')sd(x),mdy(1,1,n,L,R,x);
        else{
            y=(ll)(R-L+2)*(R-L+1)>>1;
            x=qry(1,1,n,L,R,0)*(R+1)*(1-L)+qry(1,1,n,L,R,1)*(R+L)-qry(1,1,n,L,R,2);
            g=__gcd(x,y);we(x/g),sr[C]='/',we(y/g);
        }
    }
return Ot(),0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值