P2221 [HAOI2012]高速公路

P2221 [HAOI2012]高速公路

\(n-1\)条边,查询点\((l,r)l<r\)相当于边\((l,r-1)\)
\(dis_{i,j}\)表示边\(i\)~\(j\)权之和

每次查询边\((l,r)\)

\(ans=\dfrac{\sum\limits_{i=l}^r\sum\limits_{j=i}^rdis_{i,j}}{C_{r-l+1}^2}=\dfrac{\sum\limits_{i=l}^ra_{i}(r-i+1)(i-l+1)}{((r+1)-l)((r+1)-l+1)}\)

我们来看上面这部分,拆开后

\(\sum\limits_{i=l}^ra_{i}(ri-rl+r-i^2+il-i+i-l+1)\)

\(\sum\limits_{i=l}^ra_{i}(ri-rl+r-i^2+il-l+1)\)

\(\sum\limits_{i=l}^ra_{i}(-i^2+ri+il-rl+r-l+1)\)

\(\sum\limits_{i=l}^ra_{i}((-i^2)+i(l+r)+(r+1-rl-l)\)

\(\sum\limits_{i=l}^ra_{i}(r+1-rl-l)+\sum\limits_{i=l}^ra_{i}(i(l+r))+\sum\limits_{i=l}^ra_{i}((-i^2)\)

线段树维护\(\sum\limits_{i=l}^ra_{i},\sum\limits_{i=l}^ra_{i}*i,\sum\limits_{i=l}^ra_{i}*i*i\)三个值就行了

现在考虑区间修改时怎么拆开上面的式子,假设\((l,r)\)加上\(val\)

\(sum1+=val(r-l+1)\)

\(sum2+=val[(l+r)(r-l+1)/2]\)

维护\(sum3\)要用到一个常用公式了,不会自行百度\(\sum\limits_{i=1}^ni^2=\dfrac {n(n+1)(2n+1)}{6}\)

\(sum3+=val\dfrac {r(r+1)(2r+1)-(l-1)[(l-1)+1][2(l-1)+1]}{6}\)

其他的就是类似模板的东西了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL maxn=1e7+1;
inline LL Read(){
    LL x=0,f=1; char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-') f=-1; c=getchar();
    }
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*f;
}
struct node{
    LL lazy;
    LL sum1,sum2,sum3;
    LL son[2];
}tree[maxn];
LL n,m,nod,root;
inline void Update(LL now){
    LL son0=tree[now].son[0]; LL son1=tree[now].son[1];
    tree[now].sum1=tree[son0].sum1+tree[son1].sum1,
    tree[now].sum2=tree[son0].sum2+tree[son1].sum2,
    tree[now].sum3=tree[son0].sum3+tree[son1].sum3;
}
inline void Pushdown(LL now,LL l,LL r){
    if(!tree[now].lazy)
        return;
    LL val=tree[now].lazy;
    if(!tree[now].son[0]) tree[now].son[0]=++nod; LL son0=tree[now].son[0]; 
    if(!tree[now].son[1]) tree[now].son[1]=++nod; LL son1=tree[now].son[1]; 
    LL mid=(l+r)>>1; LL l1=l,r1=mid,l2=mid+1,r2=r;
    tree[son0].lazy+=val,
    tree[son0].sum1+=(r1-l1+1)*val,
    tree[son0].sum2+=(l1+r1)*(r1-l1+1)/2*val,
    tree[son0].sum3+=((r1*(r1+1)*(2*r1+1)-(l1-1)*((l1-1)+1)*(2*(l1-1)+1))/6)*val,
    tree[son1].lazy+=val,
    tree[son1].sum1+=(r2-l2+1)*val,
    tree[son1].sum2+=(l2+r2)*(r2-l2+1)/2*val,
    tree[son1].sum3+=((r2*(r2+1)*(2*r2+1)-(l2-1)*((l2-1)+1)*(2*(l2-1)+1))/6)*val,
    tree[now].lazy=0;
}
void Add(LL &now,LL l,LL r,LL lt,LL rt,LL val){
    if(!now)
        now=++nod;
    if(lt<=l&&rt>=r){
        tree[now].lazy+=val,
        tree[now].sum1+=(r-l+1)*val,
        tree[now].sum2+=(l+r)*(r-l+1)/2*val,
        tree[now].sum3+=((r*(r+1)*(2*r+1)-(l-1)*((l-1)+1)*(2*(l-1)+1))/6)*val;
        return;
    }
    Pushdown(now,l,r);
    LL mid=(l+r)>>1;
    if(lt<=mid)
        Add(tree[now].son[0],l,mid,lt,rt,val);
    if(rt>mid)
        Add(tree[now].son[1],mid+1,r,lt,rt,val);
    Update(now);
}
LL Query(LL &now,LL l,LL r,LL lt,LL rt){
    if(!now)
        now=++nod;
    if(lt<=l&&rt>=r)
        return (rt-lt+1-lt*rt)*tree[now].sum1+(rt+lt)*tree[now].sum2-tree[now].sum3;
    Pushdown(now,l,r);
    LL mid=(l+r)>>1,sum=0;
    if(lt<=mid)
        sum+=Query(tree[now].son[0],l,mid,lt,rt);
    if(rt>mid)
        sum+=Query(tree[now].son[1],mid+1,r,lt,rt);
    return sum;
}
LL Gcd(LL x,LL y){
    if(!y)
        return x;
    return Gcd(y,x%y);
}
int main(){
    n=Read()-1,m=Read();
    while(m--){
        char c; scanf(" %c",&c);
        LL l=Read(),r=Read()-1;
        if(c=='C'){
            LL val=Read();
            Add(root,1,n,l,r,val);
        }else{
            LL mu=Query(root,1,n,l,r),zi=((r+1)-l)*((r+1)-l+1)/2;
            LL g=Gcd(mu,zi);
            printf("%lld/%lld\n",mu/g,zi/g);
        }
    }
    return 0;
}/*
*/
posted @ 2018-12-28 23:12  y2823774827y  阅读(147)  评论(0编辑  收藏  举报