Link:
Solution:
虽然有期望,但实际上就是除了个总数……
此题计算总代价明显还是要使用对每个$w_i$计算贡献的方式:
$w_i的贡献为w_i*(i-l+1)*(r-i)$(左端点的方案数乘上右端点的方案数)
为了能使维护的数据符合$RMQ$的性质,我们要将$l,r$分离出来,拆项得到:
$-w_i*i^2+w_i*i*(l+r-1)+w_i*(r-r*l)$
求完前缀和后用3棵线段树分别维护0/1/2次项的区间和即可
Code:
#include <bits/stdc++.h> using namespace std; #define mid ((l+r)>>1) #define lc k<<1,l,mid #define rc k<<1|1,mid+1,r typedef long long ll; const int MAXN=1e5+10; char op[5]; int n,m,l,r,v; ll seg[MAXN<<2][3],tag[MAXN<<2],s1[MAXN],s2[MAXN]; void merge(int k) {for(int i=0;i<3;i++) seg[k][i]=seg[k<<1][i]+seg[k<<1|1][i];} void modify(int k,int l,int r,ll inc) { tag[k]+=inc; seg[k][0]+=inc*(r-l+1); seg[k][1]+=inc*(s1[r]-s1[l-1]); seg[k][2]+=inc*(s2[r]-s2[l-1]); } void pushdown(int k,int l,int r) { if(!tag[k]) return; modify(lc,tag[k]);modify(rc,tag[k]); tag[k]=0; } void Update(int a,int b,int x,int k,int l,int r) { if(a<=l&&r<=b){modify(k,l,r,x);return;} pushdown(k,l,r); if(a<=mid) Update(a,b,x,lc); if(b>mid) Update(a,b,x,rc); merge(k); } ll Query(int a,int b,int x,int k,int l,int r) { if(a<=l&&r<=b) return seg[k][x]; pushdown(k,l,r); ll ret=0; if(a<=mid) ret+=Query(a,b,x,lc); if(b>mid) ret+=Query(a,b,x,rc); return ret; } ll gcd(ll a,ll b) {return (a%b==0)?b:gcd(b,a%b);} int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) s1[i]=s1[i-1]+i,s2[i]=s2[i-1]+1ll*i*i; while(m--) { scanf("%s%d%d",op,&l,&r); if(op[0]=='C') scanf("%d",&v),Update(l,r-1,v,1,1,n); else { ll res=Query(l,r-1,0,1,1,n)*r*(1-l)+Query(l,r-1,1,1,1,n)*(r+l-1)-Query(l,r-1,2,1,1,n); ll div=1ll*(r-l+1)*(r-l)/2;ll GCD=gcd(res,div); printf("%lld/%lld ",res/GCD,div/GCD); } } return 0; }