题目:
题解:
这个题目期望的点就是把每一段的距离加起来然后/[(r-l+1)*(r-l)/2]
那么这道题目就剩下求每个子区间的和 的和
这个1e5的范围还有修改操作我们选择线段树
很明显权值是在边上的,这里我们已经考虑r–了,那么我们要求的值=Σcost[i]* (i-l+1)*(r-i+1)
其实并不难理解,就是包含这个数的左子集*包含这个数的右子集
然后拆开=(r-l+1-rl)Σcost[i]+(l+r)Σi*cost[i]-Σi*i*cost[i]
那么我们只需要用线段树维护Σcost[i],Σi*cost[i],Σi*i*cost[i]就好了
修改的时候随便画画柿子pushdown就行
代码:
#include <cstdio>
#include <cstring>
#define LL unsigned long long
using namespace std;
const int N=100005;
LL delta[N*4],sum[N*4],sum1[N*4],sum2[N*4],s,s1,s2;
LL pfh(LL x){return x*(x+1)*(2*x+1)/6;}
LL gcd(LL a,LL b){if (!b) return a;else return gcd(b,a%b);}
void updata(int now)
{
sum[now]=sum[now<<1]+sum[now<<1|1];
sum1[now]=sum1[now<<1]+sum1[now<<1|1];
sum2[now]=sum2[now<<1]+sum2[now<<1|1];
}
void pushdown(int now,int l,int r,int mid)
{
if (delta[now])
{
sum[now<<1]+=(LL)(mid-l+1)*delta[now];
sum[now<<1|1]+=(LL)(r-mid)*delta[now];
sum1[now<<1]+=(LL)(l+mid)*(LL)(mid-l+1)/2LL*delta[now];
sum1[now<<1|1]+=(LL)(r+mid+1)*(LL)(r-mid)/2LL*delta[now];
sum2[now<<1]+=(pfh(mid)-pfh(l-1))*delta[now];
sum2[now<<1|1]+=(pfh(r)-pfh(mid))*delta[now];
delta[now<<1]+=delta[now];
delta[now<<1|1]+=delta[now];
delta[now]=0;
}
}
void add(int now,int l,int r,int lrange,int rrange,LL v)
{
if (lrange<=l && rrange>=r)
{
sum[now]+=(LL)(r-l+1)*(LL)v; delta[now]+=v;
sum1[now]+=(LL)(l+r)*(LL)(r-l+1)/2*v;
sum2[now]+=(pfh(r)-pfh(l-1))*v;
return;
}
int mid=(l+r)>>1;pushdown(now,l,r,mid);
if (lrange<=mid) add(now<<1,l,mid,lrange,rrange,v);
if (rrange>mid) add(now<<1|1,mid+1,r,lrange,rrange,v);
updata(now);
}
void qurry(int now,int l,int r,int lrange,int rrange)
{
if (lrange<=l && rrange>=r) {s+=sum[now];s1+=sum1[now];s2+=sum2[now];return;}
int mid=(l+r)>>1;pushdown(now,l,r,mid);
if (lrange<=mid) qurry(now<<1,l,mid,lrange,rrange);
if (rrange>mid) qurry(now<<1|1,mid+1,r,lrange,rrange);
}
int main()
{
int n,m,l,r;LL v;scanf("%d%d",&n,&m);
while (m--)
{
char st[5];s=s1=s2=0;
scanf("%s",st);scanf("%d%d",&l,&r);
LL fm=(LL)(r-l+1)*(LL)(r-l)/2;r--;
if (st[0]=='C')
{
scanf("%lld",&v);
add(1,1,n,l,r,v);
}else
{
qurry(1,1,n,l,r);
LL fz=(LL)(r-l+1-(LL)r*l)*s-s2+(LL)(l+r)*s1;
LL d=gcd(fm,fz);fm/=d;fz/=d;
printf("%llu/%llu\n",fz,fm);
}
}
}