题解 - 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=l∑rai×(i−l+1)×(r−i)
这个式子没什么用,我们化简后面的式子: 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×(ri−i2−lr−li+r−i)→ai×(r−lr)+(r+l−1)×ai×i−ai×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=l∑rai,i=l∑rai×i,i=l∑rai×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;
}