题解:线段树
一开始维护错区间和,然后GG,不要凭感觉
没把调试用的函数注释掉T了一发
#include<iostream>
#include<cstdio>
#include<cstring>
#define lo now<<1
#define ro now<<1|1
using namespace std;
const int maxn=100009;
typedef long long Lint;
int n,m;
Lint si[maxn],si2[maxn];
Lint Gcd(Lint a,Lint b){
if(b==0)return a;
return Gcd(b,a%b);
}
struct SegmentTree{
int l,r;
Lint tag;
Lint tl,sum,tr,dist;
}tree[maxn<<2];
void pushup(int now){
int ll=tree[lo].l;
int lr=tree[lo].r;
int rl=tree[ro].l;
int rr=tree[ro].r;
tree[now].sum=tree[lo].sum+tree[ro].sum+tree[lo].tr*(rr-rl+1)+tree[ro].tl*(lr-ll+1);
tree[now].dist=tree[lo].dist+tree[ro].dist;
tree[now].tl=tree[lo].tl+tree[ro].tl+tree[lo].dist*(rr-rl+1);
tree[now].tr=tree[lo].tr+tree[ro].tr+tree[ro].dist*(lr-ll+1);
}
void pushdown(int now){
int son;
Lint tag=tree[now].tag;
int l,r,len;
for(int i=0;i<=1;++i){
son=(now<<1|i);
tree[son].tag+=tag;
l=tree[son].l;r=tree[son].r;len=r-l+1;
tree[son].sum+=(tag*len*si[len]-tag*si2[len]+tag*si[len]);
tree[son].tl+=tag*si[len];
tree[son].tr+=tag*si[len];
tree[son].dist+=tag*(r-l+1);
}
tree[now].tag=0;
}
void check(int now){
// printf("%d %d %d %d\n",tree[now].l,tree[now].r,tree[now].tl,tree[now].tr);
if(tree[now].l==tree[now].r)return;
pushdown(now);
check(lo);
check(ro);
}
void BuildTree(int now,int l,int r){
tree[now].l=l;tree[now].r=r;
tree[now].tag=tree[now].tl=tree[now].tr=tree[now].sum=tree[now].dist=0;
if(l==r)return;
int mid=(l+r)>>1;
BuildTree(lo,l,mid);
BuildTree(ro,mid+1,r);
}
void Updatasec(int now,int ll,int rr,Lint x){
if(tree[now].l>=ll&&tree[now].r<=rr){
tree[now].tag+=x;
int l=tree[now].l,r=tree[now].r;
int len=r-l+1;
tree[now].sum+=(x*len*si[len]-x*si2[len]+x*si[len]);
tree[now].tl+=si[len]*x;
tree[now].tr+=si[len]*x;
tree[now].dist+=(r-l+1)*x;
return;
}
pushdown(now);
int mid=(tree[now].l+tree[now].r)>>1;
if(ll<=mid)Updatasec(lo,ll,rr,x);
if(rr>mid)Updatasec(ro,ll,rr,x);
pushup(now);
}
Lint sum;
void Querysum(int now,int ll,int rr,Lint &tl,Lint &tr,Lint &len){
if(tree[now].l>=ll&&tree[now].r<=rr){
sum+=tree[now].sum;
tl=tree[now].tl;
tr=tree[now].tr;
len=tree[now].dist;
return;
}
pushdown(now);
int mid=(tree[now].l+tree[now].r)>>1;
if(rr<=mid)Querysum(lo,ll,rr,tl,tr,len);
else if(ll>mid)Querysum(ro,ll,rr,tl,tr,len);
else{
Lint a,b,c,d,e,f;
Querysum(lo,ll,rr,a,b,c);
Querysum(ro,ll,rr,d,e,f);
int lb=max(tree[lo].l,ll);
int rb=min(tree[ro].r,rr);
tl=a+d+(c)*(rb-mid);
tr=b+e+(f)*(mid-lb+1);
len=c+f;
sum+=b*(rb-mid)+d*(mid-lb+1);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
si[i]=si[i-1]+i;
si2[i]=si2[i-1]+1LL*i*i;
}
BuildTree(1,1,n-1);
while(m--){
char opty=getchar();
int x,y,z;
Lint p1,p2,p3;
while(opty!='Q'&&opty!='C')opty=getchar();
scanf("%d%d",&x,&y);
--y;
if(opty=='Q'){
sum=0;
Querysum(1,x,y,p1,p2,p3);
Lint d=Gcd(sum,si[y-x+1]);
printf("%lld/%lld\n",sum/d,si[y-x+1]/d);
}else{
scanf("%d",&z);
Updatasec(1,x,y,z*1LL);
}
// check(1);
}
return 0;
}