【题解】HAOI-2012高速公路

Problem

bzoj & Luogu

题意:给定链,每次修改区间上的权值或查询在一段区间上任取两端点的链长期望值

Solution

根据期望的性质明显得到式子 a n s = 2 i = l r 1 ( i l + 1 ) ( r i ) w i ( r l + 1 ) ( r l )

下面可以现场求,上面比较麻烦,转换一下:

i = l r 1 ( i l + 1 ) ( r i ) w i = i = l r 1 ( i 2 + ( l + r 1 ) i + ( r l r ) ) w i = i = l r 1 i 2 w i + ( l + r 1 ) i = l r 1 i w i + ( r l r ) i = l r 1 w i

这个就可以线段树求了,只用维护上式中的三个sigma,至于区间修改对答案的影响可以用 O ( 1 ) 的两个公式(今天数学课上才证的)差分一下即可:

i = 1 n i = ( 1 + n ) n 2 i = 1 n i 2 = n ( n + 1 ) ( 2 n + 1 ) 6

Code

#include<cstdio>
#include<cctype>
using namespace std;
typedef long long ll;
#define rg register

template <typename _Tp> inline _Tp read(_Tp&x){
    rg char c11=getchar(),ob=0;x=0;
    while(c11^'-'&&!isdigit(c11))c11=getchar();if(c11=='-')c11=getchar(),ob=1;
    while(isdigit(c11))x=x*10+c11-'0',c11=getchar();if(ob)x=-x;return x;
}

const int N=101000;
struct SegTree{ll s0,s1,s2;}seg[N<<2];
ll lazy[N<<2],s0,s1,s2;
int n,m;

inline ll gcd(ll A,ll B){return B?gcd(B,A%B):A;}

inline void down(int x,ll L,ll R){
    ll mid=(L+R)>>1,l,r;
    l=L,r=mid;
    seg[x<<1].s0+=1ll*lazy[x]*(r-l+1);
    seg[x<<1].s1+=1ll*lazy[x]*(l+r)*(r-l+1)>>1;
    seg[x<<1].s2+=1ll*lazy[x]*((r*(r+1)*(r<<1|1)-((l-1)*(l)*((l-1)<<1|1)))/6);
    l=mid+1,r=R;
    seg[x<<1|1].s0+=1ll*lazy[x]*(r-l+1);
    seg[x<<1|1].s1+=1ll*lazy[x]*(l+r)*(r-l+1)>>1;
    seg[x<<1|1].s2+=1ll*lazy[x]*((r*(r+1)*(r<<1|1)-((l-1)*(l)*((l-1)<<1|1)))/6);
    lazy[x<<1]+=lazy[x],lazy[x<<1|1]+=lazy[x];
    lazy[x]=0;return ;
}

inline void up(int x){
    seg[x].s0=seg[x<<1].s0+seg[x<<1|1].s0;
    seg[x].s1=seg[x<<1].s1+seg[x<<1|1].s1;
    seg[x].s2=seg[x<<1].s2+seg[x<<1|1].s2;
    return ;
}

void update(ll l,ll r,int x,int L,int R,ll alpha){
    if(L<=l&&r<=R){
        seg[x].s0+=1ll*alpha*(r-l+1);
        seg[x].s1+=1ll*alpha*(l+r)*(r-l+1)>>1;
        seg[x].s2+=1ll*alpha*((r*(r+1)*(r<<1|1)-((l-1)*(l)*((l-1)<<1|1)))/6);
        lazy[x]+=alpha;return ;
    }
    if(lazy[x])down(x,l,r);
    int mid((l+r)>>1);
    if(L<=mid)update(l,mid,x<<1,L,R,alpha);
    if(mid<R)update(mid+1,r,x<<1|1,L,R,alpha);
    up(x);return ;
}

void query(ll l,ll r,int x,int L,int R){
    if(L<=l&&r<=R){s0+=seg[x].s0,s1+=seg[x].s1,s2+=seg[x].s2;return ;}
    if(lazy[x])down(x,l,r);
    int mid((l+r)>>1);
    if(L<=mid)query(l,mid,x<<1,L,R);
    if(mid<R)query(mid+1,r,x<<1|1,L,R);
    return ;
}

int main(){
    read(n);read(m);
    ll l,r,x;char opt[2];
    while(m--){
        scanf("%s",opt);
        if(opt[0]=='C'){
            read(l),read(r),read(x);
            update(1,n,1,l,r-1,x);
        }else {
            read(l),read(r);
            s0=s1=s2=0;query(1,n,1,l,r-1);
            ll a1=1ll*2*(-s2+(l+r-1)*s1+(r-l*r)*s0);
            ll a2=1ll*(r-l+1)*(r-l);
            ll com=gcd(a1,a2);
            a1/=com,a2/=com;
            printf("%lld/%lld\n",a1,a2);
        }
    }return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40515553/article/details/80370388