洛谷2221 [HAOI2012]高速公路(线段树)
传送门
【题目分析】
蒟蒻考完只能刷水题,还被水题翻来覆去的吊打qwq
对于给定区间[l,r],考虑计算它的期望费用,就是 总的费用/总的情况数
总的情况数很好确定,我选择规定可以第一次选的比第二次大,所以计算总贡献后要乘2。
然后考虑计算总的费用。
考虑一个点i,,那么他能产生的贡献就是包含该点的区间数*该点费用,总的费用公式就是下面这个式子:
,然后把括号打开,得到
整理一下:
所以很明显了,线段树维护就行了。
菜的忘记区间加要乘上一个区间长度了。。。qwq
【代码~】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL MAXN=1e5+10;
LL n,q;
LL a[MAXN];
struct Tree{
LL add;
LL l,r,pre1,pre2;
LL sum1,sum2,sum3;
}tr[MAXN<<2];
struct data{
LL ans1,ans2,ans3;
data(LL x=0,LL y=0,LL z=0){
ans1=x,ans2=y,ans3=z;
}
friend inline data operator+(const data &a,const data &b){
return data(a.ans1+b.ans1,a.ans2+b.ans2,a.ans3+b.ans3);
}
void init(){
ans1=ans2=ans3=0;
}
}ans;
LL Read(){
LL i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
void push_up(LL root){
tr[root].sum1=tr[root<<1].sum1+tr[root<<1|1].sum1;
tr[root].sum2=tr[root<<1].sum2+tr[root<<1|1].sum2;
tr[root].sum3=tr[root<<1].sum3+tr[root<<1|1].sum3;
}
void push_now(LL root,LL v){
tr[root].add+=v;
tr[root].sum1+=v*(tr[root].r-tr[root].l+1);
tr[root].sum2+=v*tr[root].pre1;
tr[root].sum3+=v*tr[root].pre2;
}
void push_down(LL root){
if(tr[root].add!=0){
push_now(root<<1,tr[root].add);
push_now(root<<1|1,tr[root].add);
tr[root].add=0;
}
}
void build(LL root,LL l,LL r){
tr[root].l=l,tr[root].r=r;
if(l==r){
tr[root].pre1=l;
tr[root].pre2=l*l;
return ;
}
LL mid=l+r>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
push_up(root);
tr[root].pre1=tr[root<<1].pre1+tr[root<<1|1].pre1;
tr[root].pre2=tr[root<<1].pre2+tr[root<<1|1].pre2;
}
void update(LL root,LL l,LL r,LL L,LL R,LL key){
if(l>R||r<L)
return ;
if(L<=l&&r<=R){
push_now(root,key);
return ;
}
push_down(root);
LL mid=l+r>>1;
if(R<=mid)
update(root<<1,l,mid,L,R,key);
else{
if(L>mid)
update(root<<1|1,mid+1,r,L,R,key);
else
update(root<<1,l,mid,L,mid,key),update(root<<1|1,mid+1,r,mid+1,R,key);
}
push_up(root);
}
void query(LL root,LL l,LL r,LL L,LL R){
if(l>R||r<L)
return ;
if(L<=l&&r<=R){
ans=ans+data(tr[root].sum1,tr[root].sum2,tr[root].sum3);
return ;
}
push_down(root);
data a;
LL mid=l+r>>1;
if(R<=mid){
query(root<<1,l,mid,L,R);
return ;
}
else{
if(L>mid){
query(root<<1|1,mid+1,r,L,R);
return ;
}
else{
query(root<<1,l,mid,L,mid),query(root<<1|1,mid+1,r,mid+1,R);
return ;
}
}
}
LL gcd(LL x,LL y){
return x%y?gcd(y,x%y):y;
}
int main(){
n=Read(),q=Read();
build(1,1,n-1);
while(q--){
char cz[5];
LL l,r;
scanf("%s",cz);
l=Read(),r=Read();
if(cz[0]=='C'){
LL key=Read();
update(1,1,n-1,l,r-1,key);
}
else{
ans.init();
query(1,1,n-1,l,r-1);
LL fz=2*(-r*(l-1)*ans.ans1+(r+l-1)*ans.ans2-ans.ans3);
LL fm=(r-l+1)*(r-l);
LL gc=gcd(fz,fm);
cout<<fz/gc<<'/'<<fm/gc<<'\n';
}
}
return 0;
}