洛谷P2221 线段树+概率

考虑每条路做的贡献,比左端点小的端点数*比右端点大的端点数

推一下柿子就发现要在线段树上分别维护 vi, i*vi, i*i*vi的区间和,好久没写了QAQ

考虑区间加操作对区间和的影响,在pushdown,update里加上影响

#include<bits/stdc++.h>
#define lll long long
#define l o<<1
#define r o<<1|1
using namespace std;

lll sum1[500005],sum2[500005],sum3[500005];//vi i*vi i*i*vi的线段树 
lll lz[500005];

lll cal(lll L,lll R){//i*i的(l,r)部分和 
    L--;
    return R*(R+1)*(2*R+1)/6-L*(L+1)*(2*L+1)/6;
}
void pushup(lll o){
   sum1[o]=sum1[l]+sum1[r];
   sum2[o]=sum2[l]+sum2[r];
   sum3[o]=sum3[l]+sum3[r];
}
void pushdown(lll L,lll R,lll o){
    if(lz[o]!=0){
        lll m=(L+R)>>1;
        lz[l]+=lz[o];lz[r]+=lz[o];
        sum1[l]+=(m-L+1)*lz[o];
        sum1[r]+=(R-m)*lz[o];

        sum2[l]+=lz[o]*(L+m)*(m-L+1)/2;//这里不是lz[l]!!! ,lz[l]是给o的左儿子l的左右儿子加的 
        sum2[r]+=lz[o]*(m+1+R)*(R-m)/2;

        sum3[l]+=lz[o]*cal(L,m);
        sum3[r]+=lz[o]*cal(m+1,R);

        lz[o]=0;
    }
}

lll query1(lll ql,lll qr,lll L,lll R,lll o,lll ty){//鏌ヨsum1
    if(ql<=L&&qr>=R){//褰撳墠鏄瓙鍖洪棿
        if(ty==1)return sum1[o];
        if(ty==2)return sum2[o];
        if(ty==3)return sum3[o];
    }
    lll m=(L+R)>>1;lll ans=0;
    pushdown(L,R,o);
    if(ql<=m)ans+=query1(ql,qr,L  ,m,l,ty);
    if(qr>m) ans+=query1(ql,qr,m+1,R,r,ty);
    return ans;
}

void update(lll ql,lll qr,lll L,lll R,lll o,lll val){
    if(ql<=L&&qr>=R){
    	lz[o]+=val;
        sum1[o]+=(R-L+1)*val;
        sum2[o]+=(L+R)*(R-L+1)/2*val;
        sum3[o]+=cal(L,R)*val;
        return;
    }
    lll m=(L+R)>>1;
    pushdown(L,R,o);
    if(ql<=m)update(ql,qr,L  ,m,l,val);
    if(qr>m) update(ql,qr,m+1,R,r,val);
    pushup(o);
}

int main(){
    //ios::sync_with_stdio(false);
    int n,q;scanf("%d %d",&n,&q);
	memset(sum1,0,sizeof(sum1));
	memset(sum2,0,sizeof(sum2));
	memset(sum3,0,sizeof(sum3));
	memset(lz,0,sizeof(lz));
    while(q--){
        char c[2];
        scanf("%s",&c);
        if(c[0]=='C'){
            lll ll,rr,vv;scanf("%lld %lld %lld",&ll,&rr,&vv);rr--;
            update(ll,rr,1,n,1,vv);
        }else{
            lll ll,rr;scanf("%lld %lld",&ll,&rr);rr--;
            lll ans1=query1(ll,rr,1,n,1,1)*(rr-ll+1-rr*ll)+
                     query1(ll,rr,1,n,1,2)*(rr+ll)+
                     query1(ll,rr,1,n,1,3)*(-1);
            lll ans2=(rr-ll+2)*(rr-ll+1)/2;
            lll gcd=__gcd(ans1,ans2);
            printf("%lld/%lld\n",ans1/gcd,ans2/gcd);
        }
    }
    system("pause");
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值