2752: [HAOI2012]高速公路(road)

题目链接

题目大意:给出一个n个结点,n-1条边的链,边权初始为0;
m次操作,操作有两种:
1. C:区间[l,r]的边权加上或减去一个数;
2. Q:查询区间随机取不相同两点之间的期望长度;

题解:根据期望的定义直接计算,总状态数共 (rl+1)(rl)2

v[i] (i,i+1) 的边权,其产生贡献的条件为同时选了其左边(包括i本身)和右边的点,即 v[i](il+1)(ri)
展开得到 v[i](rlr)+v[i]i(l+r1)v[i]i2

所以只需要维护 v[i],v[i]i,v[i]ii ,用线段树可以很方便地维护

注意修改的时候也是r-1

我的收获:线段树大法~~暴力算期望

#include <bits/stdc++.h>
using namespace std;  

#define ll long long  
#define N 100005 

int n,q;
ll si[N],sii[N];//前缀和

struct node{
    ll a1,a2,a3;
    node(){}
    node(ll _,ll __,ll ___){a1=_,a2=__,a3=___;}
};

node operator +(node x,node y){return node(x.a1+y.a1,x.a2+y.a2,x.a3+y.a3);}

struct SegmentTree{

    #define ls x<<1
    #define rs x<<1|1
    #define lson l,m,x<<1
    #define rson m+1,r,x<<1|1
    #define root 1,n,1

    ll len[N<<2],gas[N<<2],kel[N<<2];//for update 
    ll add[N<<2];//lazy-tag
    ll sum[N<<2],sui[N<<2],ali[N<<2];//sum(a_i),sum(a_i*i),sum(a_i*i*i) 

    inline void matain(int x,long long v){add[x]+=v,sum[x]+=v*len[x];sui[x]+=v*gas[x];ali[x]+=v*kel[x];}

    inline void pushdown(int x)
    {
        if(!add[x]) return ;
        matain(ls,add[x]),matain(rs,add[x]);
        add[x]=0;
    }

    inline void pushup(int x){sum[x]=sum[ls]+sum[rs],sui[x]=sui[ls]+sui[rs],ali[x]=ali[ls]+ali[rs];}

    void build(int l,int r,int x)
    {
        len[x]=r-l+1;
        gas[x]=si[r]-si[l-1];
        kel[x]=sii[r]-sii[l-1];
        if(l==r) return ;
        int m=l+r>>1;
        build(lson),build(rson);
    }

    void modify(int L,int R,int v,int l,int r,int x)
    {
        if(L<=l&&r<=R){matain(x,v);return ;}
        pushdown(x);
        int m=l+r>>1;
        if(L<=m) modify(L,R,v,lson);
        if(R>m) modify(L,R,v,rson);
        pushup(x);
    }

    node query(int L,int R,int l,int r,int x)
    {
        if(L<=l&&r<=R) return node(sum[x],sui[x],ali[x]);
        pushdown(x);
        int m=l+r>>1;
        if(L<=m&&R>m) return query(L,R,lson)+query(L,R,rson);
        if(L<=m) return query(L,R,lson);
        if(R>m) return query(L,R,rson);
    }
}T;

void work()
{
    int x,y,z;char opt[10];
    while(q--){
        scanf("%s%d%d",opt,&x,&y);
        if(opt[0]=='C') scanf("%d",&z),T.modify(x,y-1,z,root);
        else{
            node ans=T.query(x,y-1,root);
            ll fz=ans.a1*(y-1ll*x*y)+ans.a2*(x+y-1)-ans.a3;
            ll fm=1ll*(y-x+1)*(y-x)/2;
            ll g=__gcd(fz,fm);
            printf("%lld/%lld\n",fz/g,fm/g);
        }
    }
}

void init()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) si[i]=si[i-1]+i,sii[i]=sii[i-1]+1ll*i*i;
    T.build(root);
}

int main()
{  
    init(); 
    work();
    return 0;  
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值