zoukankan      html  css  js  c++  java
  • bzoj 2752

    一道看似是期望,其实与期望关系并不是特别大的题...

    首先分析一下题意:

    虽然题目中提到的是边,但事实上完全可以把每一条边的贡献放进左端点上(因为无论从哪个方向经过这条边都是计算左端点的代价)

    (题目中的提示多么明显啊!!!收费站显然是按点收费嘛...)

    因此,在修改区间$[l,r]$的边权时,我们事实上修改的是区间$[l,r-1]$的点权!

    这不就是个线段树了嘛

    可是...怎么算期望呢?

    首先把式子列出来:设我们要求的区间是$[l,r]$,直接计算整个区间的期望有点困难,我们单独讨论每个点的贡献,那么对任意$pin [l,r]$,设这个点的代价为$v_{p}$,有:

    $E(p)=frac{(p-l+1)*(r-p)*v_{p}}{C_{r-l+1}^{2}}$

    那么整个区间的期望就是:

    $sum_{i=l}^{r}E(i)$

    首先发现分母是定值,可以直接提出来,那么我们直接研究这个表达式就可以:

    $sum_{i=l}^{r}(i-l+1)*(r-i)*v_{i}$

    发现就整个区间而言,这并不太好维护,因此我们展开上述表达式:

    $sum_{i=l}^{r}(l+r-1)*i*v_{i}-sum_{i=l}^{r}i^{2}*v_{i}-sum_{i=l}^{r}*(l*r-r)*v_{i}$

    这个表达式里面所有与$l,r$有关项的都被提了出来作为系数,直接维护后面的值即可

    因此我们要维护的东西就变成了

    $sum v_{i}$,$sum i*v_{i}$与$sum i^{2}*v_{i}$

    这三个东西都可以用线段树搞定嘛

    需要用到一个公式:

    $sum_{i=1}^{n}i^{2}=frac{n*(n+1)*(2n+1)}{6}$

    这就完事了

    (网上大部分的题解给出的表达式会长这样:$E(p)=frac{(p-l+1)*(r-p+1)*v_{p}}{C_{r-l+2}^{2}}$,然后每次询问$r--$,这两种做法是完全等价的,但是个人认为我的公式更好理解,因为这个点本身当做终点是不会产生任何贡献的,因此不必进行$r--$也可以搞出正确的公式)

    贴代码:

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #define ll long long
    #define rt1 rt<<1
    #define rt2 (rt<<1)|1
    using namespace std;
    struct Seg_tree
    {
        ll val_sum;
        ll sig_sum;
        ll sqr_sum;
        ll lazy;
    }tree[400005];
    char ch[5];
    int n,m;
    void pushdown(int rt,int l,int r)
    {
        int mid=(l+r)>>1;
        tree[rt1].val_sum+=1ll*(mid-l+1)*tree[rt].lazy;
        tree[rt2].val_sum+=1ll*(r-mid)*tree[rt].lazy;
        tree[rt1].sig_sum+=(l+mid)*1ll*(mid-l+1)/2*1ll*tree[rt].lazy;
        tree[rt2].sig_sum+=1ll*(mid+1+r)*(r-mid)/2*tree[rt].lazy;
        tree[rt1].sqr_sum+=tree[rt].lazy*(mid*1ll*(mid+1)*(2ll*mid+1)/6-(l-1)*1ll*l*(2ll*l-1)/6);
        tree[rt2].sqr_sum+=tree[rt].lazy*(r*1ll*(r+1)*(2ll*r+1)/6-mid*1ll*(mid+1)*(2ll*mid+1)/6);
        tree[rt1].lazy+=tree[rt].lazy;
        tree[rt2].lazy+=tree[rt].lazy;
        tree[rt].lazy=0;
    }
    void pushup(int rt)
    {
        tree[rt].val_sum=tree[rt1].val_sum+tree[rt2].val_sum;
        tree[rt].sig_sum=tree[rt1].sig_sum+tree[rt2].sig_sum;
        tree[rt].sqr_sum=tree[rt1].sqr_sum+tree[rt2].sqr_sum;
    }
    void update(int rt,int l,int r,int lq,int rq,ll w)
    {
        if(l>=lq&&r<=rq)
        {
            tree[rt].val_sum+=w*(r-l+1);
            tree[rt].sig_sum+=w*(1ll*l+r)*1ll*(r-l+1)/2;
            tree[rt].sqr_sum+=w*(1ll*r*1ll*(r+1)*(2ll*r+1)/6-1ll*(l-1)*1ll*l*(2ll*l-1)/6);
            tree[rt].lazy+=w;
            return;
        }
        pushdown(rt,l,r);
        int mid=(l+r)>>1;
        if(lq<=mid)update(rt1,l,mid,lq,rq,w);
        if(rq>mid)update(rt2,mid+1,r,lq,rq,w);
        pushup(rt);
    }
    Seg_tree query(int rt,int l,int r,int lq,int rq)
    {
        if(l>=lq&&r<=rq)return tree[rt];
        pushdown(rt,l,r);
        int mid=(l+r)>>1;
        Seg_tree ret=(Seg_tree){0,0,0,0};
        if(lq<=mid)
        {
            Seg_tree temp=query(rt1,l,mid,lq,rq);
            ret.val_sum+=temp.val_sum;
            ret.sig_sum+=temp.sig_sum;
            ret.sqr_sum+=temp.sqr_sum;
        }
        if(rq>mid)
        {
            Seg_tree temp=query(rt2,mid+1,r,lq,rq);
            ret.val_sum+=temp.val_sum;
            ret.sig_sum+=temp.sig_sum;
            ret.sqr_sum+=temp.sqr_sum;
        }
        return ret;
    }
    ll gcd(ll x,ll y)
    {
        return y?gcd(y,x%y):x;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        while(m--)
        {
            scanf("%s",ch);
            if(ch[0]=='C')
            {
                int l,r;
                ll w;
                scanf("%d%d%lld",&l,&r,&w);
                r--;
                update(1,1,n,l,r,w);
            }else
            {
                int l,r;
                scanf("%d%d",&l,&r);
                Seg_tree ans=query(1,1,n,l,r);
                ll mot=1ll*(r-l+1)*1ll*(r-l)/2;
                ll son=1ll*(l+r-1)*ans.sig_sum-1ll*(1ll*l*r-r)*ans.val_sum-ans.sqr_sum;
                ll d=gcd(mot,son);
                mot/=d,son/=d;
                printf("%lld/%lld
    ",son,mot);
            }
        }
        return 0;
    }
  • 相关阅读:
    理解MySQL——索引与优化(转)
    C# 实现3Des加密 解密
    des加密解密源码 C# key值问题
    深入浅出mysql优化--一篇博客让你精通mysql优化策略--中
    深入浅出mysql优化--一篇博客让你精通mysql优化策略--上
    深入浅出mysql优化--了解mysql常用索引结构
    从零开始了解多线程 之 深入浅出AQS -- 下(Tools&CountDownLatch&CyclicBarrier&Semaphore)
    从零开始了解多线程 之 深入浅出AQS -- 上
    从零开始了解多线程知识之开始篇目 -- jvm&volatile
    利用doxygen提高源代码阅读效率
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10952068.html
Copyright © 2011-2022 走看看