BZOJ 2752: [HAOI2012]高速公路(road)(线段树)

解题思路

  对于一段区间考虑每条边的贡献,即\(ans=\sum\limits_{i=l}^{r-1}(i-l+1)*(r-i)*w(i)\),把这个暴力展开,得到一个关于\(i\)的多项式,然后发现只需要维护\(\suma(i)\)\(\suma(i)*i\)\(\suma(i)*i^2\),线段树维护即可。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#define int long long

using namespace std;
const int N=100005;
typedef long long LL;

inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) f=ch=='-'?0:1,ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    return f?x:-x;
}

int n,m;
LL sum0[N<<2],sum1[N<<2],sum2[N<<2];
LL tag0[N<<2],tag1[N<<2],tag2[N<<2];
LL a1[N],a2[N];

inline void pushdown(int x,int l,int r){
    int mid=(l+r)>>1;
    if(tag0[x]){
        sum0[x<<1]+=tag0[x]*(mid-l+1);
        sum0[x<<1|1]+=tag0[x]*(r-mid);
        tag0[x<<1]+=tag0[x]; tag0[x<<1|1]+=tag0[x];
        tag0[x]=0;
    }
    if(tag1[x]){
        sum1[x<<1]+=tag1[x]*(a1[mid]-a1[l-1]);
        sum1[x<<1|1]+=tag1[x]*(a1[r]-a1[mid]);
        tag1[x<<1]+=tag1[x]; tag1[x<<1|1]+=tag1[x];
        tag1[x]=0;
    }
    if(tag2[x]){
        sum2[x<<1]+=tag2[x]*(a2[mid]-a2[l-1]);
        sum2[x<<1|1]+=tag2[x]*(a2[r]-a2[mid]);
        tag2[x<<1]+=tag2[x]; tag2[x<<1|1]+=tag2[x];
        tag2[x]=0;
    }
}

void update(int x,int l,int r,int L,int R,int k){
    if(L<=l && r<=R) {
        sum0[x]+=(r-l+1)*k; tag0[x]+=k;
        sum1[x]+=(LL)(a1[r]-a1[l-1])*k; tag1[x]+=k;
        sum2[x]+=(LL)(a2[r]-a2[l-1])*k; tag2[x]+=k;
        return ;
    }
    int mid=(l+r)>>1;pushdown(x,l,r);
    if(L<=mid) update(x<<1,l,mid,L,R,k);
    if(mid<R) update(x<<1|1,mid+1,r,L,R,k);
    sum0[x]=sum0[x<<1]+sum0[x<<1|1];
    sum1[x]=sum1[x<<1]+sum1[x<<1|1];
    sum2[x]=sum2[x<<1]+sum2[x<<1|1];
}

LL query0(int x,int l,int r,int L,int R){
    if(L<=l && r<=R) return sum0[x];
    int mid=(l+r)>>1; LL ret=0; pushdown(x,l,r);
    if(L<=mid) ret+=query0(x<<1,l,mid,L,R);
    if(mid<R) ret+=query0(x<<1|1,mid+1,r,L,R);
    return ret;
}

LL query1(int x,int l,int r,int L,int R){
    if(L<=l && r<=R) return sum1[x];
    int mid=(l+r)>>1; LL ret=0; pushdown(x,l,r);
    if(L<=mid) ret+=query1(x<<1,l,mid,L,R);
    if(mid<R) ret+=query1(x<<1|1,mid+1,r,L,R);
    return ret;
}

LL query2(int x,int l,int r,int L,int R){
    if(L<=l && r<=R) return sum2[x];
    int mid=(l+r)>>1; LL ret=0; pushdown(x,l,r);
    if(L<=mid) ret+=query2(x<<1,l,mid,L,R);
    if(mid<R) ret+=query2(x<<1|1,mid+1,r,L,R);
    return ret;
}

LL gcd(LL x,LL y){
    if(!y) return x;
    return gcd(y,x%y);
}

signed main(){
    n=rd(),m=rd(); 
    for(int i=1;i<n;i++) a1[i]=a1[i-1]+i;
    for(int i=1;i<n;i++) a2[i]=a2[i-1]+(LL)i*i;
    char c; int l,r,k; LL ans,now,GCD;
    while(m--){
        c=getchar(); while(c!='C' && c!='Q') c=getchar();
        if(c=='C'){
            l=rd(),r=rd()-1,k=rd();
            update(1,1,n,l,r,k);
        }
        else {
            l=rd(),r=rd()-1; now=(r-l+2)*(r-l+1)/2;
            ans=-query2(1,1,n,l,r)+query1(1,1,n,l,r)*(l+r)-query0(1,1,n,l,r)*(l*r+l-r-1);
            GCD=gcd(ans,now); ans/=GCD; now/=GCD;
            printf("%lld/%lld\n",ans,now);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/sdfzsyq/p/10286071.html