题解 - P2221

题解 - P 2221 \mathrm{P2221} P2221

题目描述

题目链接

S o l \mathrm{Sol} Sol

一道线段树维护数列题。

首先我们考虑每次询问的贡献 V ( l , r ) = ∑ i = l r a i × ( i − l + 1 ) × ( r − i ) V_{(l,r)}=\sum\limits_{i=l}^{r}a_i\times(i-l+1)\times (r-i) V(l,r)=i=lrai×(il+1)×(ri)

这个式子没什么用,我们化简后面的式子: a i × ( r i − i 2 − l r − l i + r − i ) → a i × ( r − l r ) + ( r + l − 1 ) × a i × i − a i × i 2 a_i\times(ri-i^2-lr-li+r-i)\to a_i\times(r-lr)+(r+l-1)\times a_i\times i-a_i\times i^2 ai×(rii2lrli+ri)ai×(rlr)+(r+l1)×ai×iai×i2

对于 ∑ i = l r a i , ∑ i = l r a i × i , ∑ i = l r a i × i 2 \sum\limits_{i=l}^ra_i,\sum\limits_{i=l}^ra_i\times i,\sum\limits_{i=l}^ra_i\times i^2 i=lrai,i=lrai×i,i=lrai×i2 可以用线段树进行维护

时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)

C o d e \mathrm{Code} Code


const int N=1e5+5;

struct Seg
{
    
    
    int s1,s2,s3;
    int s4,s5,laz;
};
Seg tr[N<<2];
int n,m;

inline int gcd(int x,int y)
{
    
    
    return (!y)?x:gcd(y,x%y);
}

inline void build(int x,int l,int r)
{
    
    
    if(l==r)
    {
    
    
        tr[x].s4=l;
        tr[x].s5=l*l;
        return;
    }
    int mid=l+r>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
    tr[x].s4=tr[x<<1].s4+tr[x<<1|1].s4;
    tr[x].s5=tr[x<<1].s5+tr[x<<1|1].s5;
}

inline void pushdown(int x,int l,int r)
{
    
    
    if(tr[x].laz)
    {
    
    
        int mid=l+r>>1;
        int v=tr[x].laz;
        tr[x<<1].s1+=(mid-l+1)*v;
        tr[x<<1|1].s1+=(r-mid)*v;
        tr[x<<1].s2+=v*tr[x<<1].s4;
        tr[x<<1|1].s2+=v*tr[x<<1|1].s4;
        tr[x<<1].s3+=v*tr[x<<1].s5;
        tr[x<<1|1].s3+=v*tr[x<<1|1].s5;
        tr[x<<1].laz+=v;
        tr[x<<1|1].laz+=v;
        tr[x].laz=0;
    }
}

inline void fix(int x,int l,int r,int ll,int rr,int v)
{
    
    
    if(ll>r||rr<l) return;
    if(ll<=l&&r<=rr)
    {
    
    
        tr[x].s1+=(r-l+1)*v;
        tr[x].s2+=v*tr[x].s4;
        tr[x].s3+=v*tr[x].s5;
        tr[x].laz+=v;
        return;
    }
    int mid=l+r>>1;
    pushdown(x,l,r);
    fix(x<<1,l,mid,ll,rr,v);
    fix(x<<1|1,mid+1,r,ll,rr,v);
    tr[x].s1=tr[x<<1].s1+tr[x<<1|1].s1;
    tr[x].s2=tr[x<<1].s2+tr[x<<1|1].s2;
    tr[x].s3=tr[x<<1].s3+tr[x<<1|1].s3;
}

inline int Ask(int x,int l,int r,int ll,int rr,int op)
{
    
    
    if(ll>r||rr<l) return 0;
    if(ll<=l&&r<=rr)
    {
    
    
        if(op==1) return tr[x].s1;
        if(op==2) return tr[x].s2;
        if(op==3) return tr[x].s3;
    }
    int mid=l+r>>1;
    pushdown(x,l,r);
    int s1=0,s2=0,s3=0;
    if(ll<=mid)
    {
    
    
        if(op==1) s1+=Ask(x<<1,l,mid,ll,rr,1);
        if(op==2) s2+=Ask(x<<1,l,mid,ll,rr,2);
        if(op==3) s3+=Ask(x<<1,l,mid,ll,rr,3);
    }
    if(rr>mid)
    {
    
    
        if(op==1) s1+=Ask(x<<1|1,mid+1,r,ll,rr,1);
        if(op==2) s2+=Ask(x<<1|1,mid+1,r,ll,rr,2);
        if(op==3) s3+=Ask(x<<1|1,mid+1,r,ll,rr,3);
    }
    if(op==1) return s1;
    if(op==2) return s2;
    if(op==3) return s3;
}

signed main()
{
    
    
    io.read(n),io.read(m);
    build(1,1,n-1);
    for (; m--;)
    {
    
    
        char opt;
        io.Read(opt);
        int l,r,v;
        io.read(l),io.read(r);
        if(opt=='C') io.read(v),fix(1,1,n-1,l,r-1,v);
        else
        {
    
    
            int s1=Ask(1,1,n-1,l,r-1,1);
            int s2=Ask(1,1,n-1,l,r-1,2);
            int s3=Ask(1,1,n-1,l,r-1,3);
            int tot=(r-l*r)*s1+(r+l-1)*s2-s3;
            int len=(r-l+1)*(r-l)>>1ll;
            int G=gcd(tot,len);
            tot/=G,len/=G;
            io.write(tot),putchar('/'),io.write(len),puts("");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wangyiyang2/article/details/108980172