P2221 [HAOI2012]高速公路

P2221 [HAOI2012]高速公路

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

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

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

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

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

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

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

(sumlimits_{i=l}^ra_{i}((-i^2)+i(l+r)+(r+1-rl-l))

(sumlimits_{i=l}^ra_{i}(r+1-rl-l)+sumlimits_{i=l}^ra_{i}(i(l+r))+sumlimits_{i=l}^ra_{i}((-i^2))

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

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

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

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

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

(sum3+=valdfrac {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
",mu/g,zi/g);
        }
    }
    return 0;
}/*
*/
原文地址:https://www.cnblogs.com/y2823774827y/p/10193345.html