PS(请无视):天哪第一次评测窝调试中间输出没删你告诉我RE!!。。还好我无意瞟到了不然还有完没完啊。
我们发现第N个收费站是没有用的。。然后在操作时将r--简化操作。首先那个期望是很坑爹的。实际上,期望可以用总和/总状态数解决,我们不妨设a<b,这样期望不变(因为a≠b),从而总状态数即(r-l+2)*(r-l+1)/2。然后考虑总和,我们对每一个收费站单独分析。对于收费站i,它对总和的贡献为v[i]*(i-l+1)*(r-i+1),可以发现(i-l+1)*(r-i+1)即经过i的路径的条数。因此查询l,r的总和即Σ(i=l,r) v[i]*(i-l+1)*(r-i+1)。
然后就变成了区间修改区间查询的经典线段树题目了(不过好像并没有什么转化)
但是直接维护答案(或者用几个辅助数组)是会写疯掉的。。(←亲身体验)。我们把查询的那个式子展开,然后以i为主元降幂排列把那个式子化成:
Σ(i=l,r) -i^2 *a[i]+i*a[i]*(l+r)-(r+1)*(l-1)*a[i]=-Σ(i=l,r)-i^2 *a[i]+(l+r)Σ(i=1,r)i*a[i]-(r+1)*(l-1)Σ(i=l,r)a[i]
然后我们就只需要维护i*i*a[i],i*a[i],a[i]的区间和了。线段树轻松胜任。最后输出的时候再转化一下就好了。
AC代码如下(附一个暴力):
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define N 600005
using namespace std;
int n,m,c[N][2]; ll gas[N],sz[N],add[N];
struct node{ ll t1,t2,t3; }val[N];
int read(){
int x=0,fu=1; char ch=getchar();
while (ch<'0' || ch>'9'){ if (ch=='-') fu=-1; ch=getchar(); }
while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
return x*fu;
}
void build(int k,int l,int r){
c[k][0]=l; c[k][1]=r; int mid=(l+r)>>1;
if (l==r) return; build(k<<1,l,mid); build(k<<1|1,mid+1,r);
}
void maintain(int k){
int l=k<<1,r=l|1; val[k].t1=val[l].t1+val[r].t1;
val[k].t2=val[l].t2+val[r].t2; val[k].t3=val[l].t3+val[r].t3;
}
void mdy(int k,ll v){
int l=c[k][0],r=c[k][1]; add[k]+=v;
val[k].t2+=v*(gas[r]-gas[l-1]);
val[k].t1+=v*(sz[r]-sz[l-1]); val[k].t3+=v*(r-l+1);
}
void pushdown(int k){
if (add[k]){ mdy(k<<1,add[k]); mdy(k<<1|1,add[k]); add[k]=0; }
}
void ins(int k,int x,int y,ll v){
int l=c[k][0],r=c[k][1],mid=(l+r)>>1;
if (l==x && r==y){ mdy(k,v); return; }
pushdown(k);
if (y<=mid) ins(k<<1,x,y,v); else
if (x>mid) ins(k<<1|1,x,y,v); else{
ins(k<<1,x,mid,v); ins(k<<1|1,mid+1,y,v);
}
maintain(k);
}
node qry(int k,int x,int y){
int l=c[k][0],r=c[k][1],mid=(l+r)>>1;
if (l==x && r==y) return val[k];
pushdown(k);
if (y<=mid) return qry(k<<1,x,y); else
if (x>mid) return qry(k<<1|1,x,y); else{
node u=qry(k<<1,x,mid),v=qry(k<<1|1,mid+1,y);
u.t1+=v.t1; u.t2+=v.t2; u.t3+=v.t3; return u;
}
}
ll gcd(ll x,ll y){ return (y)?gcd(y,x%y):x; }
int main(){
n=read(); m=read(); int i;
build(1,1,n); char ch;
for (i=1; i<=n; i++){ gas[i]=gas[i-1]+i; sz[i]=sz[i-1]+(ll)i*i; }
while (m--){
ch=getchar(); while (ch<'A' || ch>'Z') ch=getchar();
if (ch=='C'){
int x=read(),y=read()-1,z=read();
ins(1,x,y,(ll)z);
} else{
int x=read(),y=read()-1; node ans=qry(1,x,y);
ll fz=ans.t2*(x+y)-ans.t1-ans.t3*(y+1)*(x-1),fm=gas[y-x+1];
ll tmp=gcd(fz,fm); printf("%lld/%lld\n",fz/tmp,fm/tmp);
}
}
return 0;
}
/*
int main(){
int n,m,i,a[10]={0},sum; char ch;
scanf("%d%d",&n,&m);
while (m--){
ch=getchar(); while (ch<'A' || ch>'Z') ch=getchar();
if (ch=='C'){
int x,y,z; scanf("%d%d%d",&x,&y,&z); y--;
for (i=x; i<=y; i++) a[i]+=z;
} else{
sum=0;int x,y; scanf("%d%d",&x,&y); y--;
for (i=x; i<=y; i++) sum-=i*i*a[i];
for (i=x; i<=y; i++) sum+=(x+y)*i*a[i];
for (i=x; i<=y; i++) sum-=(y+1)*(x-1)*a[i];
printf("%d\n",sum);
}
}
}*/
by lych
2016.2.17