和Leo一起做愛線段樹/數學的好孩子之[HAOI2012]高速公路
阿新 • • 發佈:2018-11-02
Y901高速公路是一條重要的交通紐帶,政府部門建設初期的投入以及使用期間的養護費用都不低,因此政府在這條高速公路上設立了許多收費站。
Y901高速公路是一條由N-1段路以及N個收費站組成的東西向的鏈,我們按照由西向東的順序將收費站依次編號為1~N,從收費站i行駛到i+1(或從i+1行駛到i)需要收取Vi的費用。高速路剛建成時所有的路段都是免費的。
政府部門根據實際情況,會不定期地對連續路段的收費標準進行調整,根據政策漲價或降價。
無聊的小A同學總喜歡研究一些稀奇古怪的問題,他開車在這條高速路上行駛時想到了這樣一個問題:對於給定的l,r(l< r),在第l個到第r個收費站裡等概率隨機取出兩個不同的收費站a和b,那麼從a行駛到b將期望花費多少費用呢?
自從上次在樹上搞了這個操作之後
我覺得不是特別難了
我們思考暴力這個期望:
我們拆開這個式子
發現貢獻是:
暴力拆開:
實際上就是維護個區間求和
線段樹維護就好了
那麼區間加就可以維護了:
維護:
和
完。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define int long long
#define lc (p<<1)
#define rc (p<<1|1)
const int N=1e5+1000;
inline void read(int &x){
x=0;
int f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
x*=f;
}
int a[N];
int GetGCD(int x,int y){
while(y){
int tmp=y;
y=x%y;
x=tmp;
}
return x;
}
struct Node{
int lson,rson;
int sum1;//a[i]
int sum2;//a[i]*i
int sum3;//a[i]*i*i
int sum4;//i
int sum5;//i*i
int lazy;
Node(){
lson=rson=sum1=sum2=sum3=sum4=sum5=lazy=0;
}
}T[N<<2];
Node operator + (Node A,Node B){
Node C;
C.sum1=A.sum1+B.sum1;
C.sum2=A.sum2+B.sum2;
C.sum3=A.sum3+B.sum3;
C.sum4=A.sum4+B.sum4;
C.sum5=A.sum5+B.sum5;
C.lson=A.lson;
C.rson=B.rson;
return C;
}
struct Segment_Tree{
inline void PushNow(int p,int val){
T[p].sum1+=(T[p].rson-T[p].lson+1)*val;
T[p].sum2+=T[p].sum4*val;
T[p].sum3+=T[p].sum5*val;
T[p].lazy+=val;
}
inline void PushDown(int p){
if(T[p].lazy){
PushNow(lc,T[p].lazy);
PushNow(rc,T[p].lazy);
T[p].lazy=0;
}
}
inline void Build(int p,int l,int r){
T[p].lson=l;
T[p].rson=r;
if(l==r){
T[p].sum1=a[l];
T[p].sum2=a[l]*l;
T[p].sum3=a[l]*l*l;
T[p].sum4=l;
T[p].sum5=l*l;
return;
}
int mid=(l+r)>>1;
Build(lc,l,mid);
Build(rc,mid+1,r);
T[p]=T[lc]+T[rc];
}
inline void Update(int p,int l,int r,int val){
if(l<=T[p].lson&&T[p].rson<=r){
PushNow(p,val);
return;
}
int mid=(T[p].lson+T[p].rson)>>1;
PushDown(p);
if(l<=mid)Update(lc,l,r,val);
if(mid< r)Update(rc,l,r,val);
T[p]=T[lc]+T[rc];
}
Node Query(int p,int l,int r){
if(l<=T[p].lson&&T[p].rson<=r){
return T[p];
}
int mid=(T[p].lson+T[p].rson)>>1;
PushDown(p);
Node ret;
if(l<=mid)ret=ret+Query(lc,l,r);
if(mid <r)ret=ret+Query(rc,l,r);
return ret;
}
}Tree;
int n,Q;
char S[10];
signed main(){
// freopen("test.in","r",stdin);
read(n);
read(Q);
Tree.Build(1,1,n);
while(Q--){
scanf("%s",S+1);
if(S[1]=='C'){
int l,r,v;
read(l);
read(r);
r--;
read(v);
Tree.Update(1,l,r,v);
}
else{
int l,r;
read(l);
read(r);
r--;
Node Now=Tree.Query(1,l,r);
int son=(r-l+1-r*l)*Now.sum1+(r+l)*Now.sum2-Now.sum3;
// cout<<Now.sum1<<" "<<Now.sum2<<" "<<Now.sum3<<'\n';
int mother=(r-l+2)*(r-l+1)/2;
int GCD=GetGCD(son,mother);
cout<<son/GCD<<"/"<<mother/GCD<<'\n';
}
}
}