1. 程式人生 > >洛谷P2221 [HAOI2012]高速公路(線段樹+概率期望)

洛谷P2221 [HAOI2012]高速公路(線段樹+概率期望)

open alc long long const git calc gcd 一個 數列求和

傳送門

首先,答案等於$$ans=\sum_{i=l}^r\sum_{j=i}^r\frac{sum(i,j)}{C_{r-l+1}^2}$$

也就是說所有情況的和除以總的情況數

因為這是一條鏈,我們可以把邊也轉化成一個序列,用$i$表示$(i,i+1)$這一條邊,那麽只要把區間的右端點減一即可

。發現下面的$C_{r-l+1}^2$很好計算,考慮怎麽計算上面的,轉化,我們考慮每條邊會被算多少次,那麽答案變成$$\sum_{i=l}^r\sum_{j=i}^r{sum(i,j)}=\sum_{i=l}^rw_i(i-l+1)(r-i+1)$$

也就是說左端點取遍這條邊左邊的所有點,右端點也取遍右邊的所有點

化簡之後可以得到$$(r+1)(1-l)\sum w_i+(l+r)w_i*i-\sum w_i*i^2$$

然後用線段樹維護即可

ps:$\sum w_i$很好維護,$\sum w_i*i$在區間加的時候用等差數列求和公式計算貢獻,$\sum w_i*i^2$用公式$\sum_{i=1}^n i^2=\frac{(2n+1)n(n+1)}{6}$計算前綴和再相減來考慮貢獻

pps:因為區間的右端點減一了,所以組合數應該變成$C_{r-l+2}^2$

 1 //minamoto
 2 #include<bits/stdc++.h>
 3 #define ll long long
 4
using namespace std; 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 6 char buf[1<<21],*p1=buf,*p2=buf; 7 inline int read(){ 8 #define num ch-‘0‘ 9 char ch;bool flag=0;int res; 10 while(!isdigit(ch=getc())) 11 (ch==-)&&(flag=true
); 12 for(res=num;isdigit(ch=getc());res=res*10+num); 13 (flag)&&(res=-res); 14 #undef num 15 return res; 16 } 17 inline char getop(){ 18 char ch;while((ch=getc())!=C&&ch!=Q);return ch; 19 } 20 char sr[1<<21],z[20];int C=-1,Z; 21 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 22 inline void print(ll x){ 23 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 24 while(z[++Z]=x%10+48,x/=10); 25 while(sr[++C]=z[Z],--Z);sr[++C]=\n; 26 } 27 const int N=1e5+5; 28 inline ll gcd(ll a,ll b){ 29 if(!b) return a; 30 while(b^=a^=b^=a%=b); 31 return a; 32 } 33 inline ll calc(int x){return 1ll*(x<<1|1)*x*(x+1)/6;} 34 int n,m,tag[N<<2];ll sum[N<<2][3]; 35 #define ls (p<<1) 36 #define rs (p<<1|1) 37 inline void upd(int p){for(int i=0;i<3;++i)sum[p][i]=sum[ls][i]+sum[rs][i];} 38 inline void ppd(int p,int l,int r,int w){ 39 int x=r-l+1;tag[p]+=w; 40 sum[p][0]+=1ll*x*w; 41 sum[p][1]+=1ll*x*w*(l+r)>>1; 42 sum[p][2]+=1ll*w*(calc(r)-calc(l-1)); 43 } 44 inline void pd(int p,int l,int r){ 45 int mid=(l+r)>>1,w=tag[p];tag[p]=0; 46 ppd(ls,l,mid,w),ppd(rs,mid+1,r,w); 47 } 48 void update(int p,int l,int r,int ql,int qr,int w){ 49 if(ql<=l&&qr>=r) return ppd(p,l,r,w); 50 int mid=(l+r)>>1;if(tag[p]) pd(p,l,r); 51 if(ql<=mid) update(ls,l,mid,ql,qr,w); 52 if(qr>mid) update(rs,mid+1,r,ql,qr,w); 53 upd(p); 54 } 55 ll query(int p,int l,int r,int ql,int qr,int t){ 56 if(ql<=l&&qr>=r) return sum[p][t]; 57 int mid=(l+r)>>1;ll res=0;if(tag[p]) pd(p,l,r); 58 if(ql<=mid) res+=query(ls,l,mid,ql,qr,t); 59 if(qr>mid) res+=query(rs,mid+1,r,ql,qr,t); 60 return res; 61 } 62 int main(){ 63 // freopen("testdata.in","r",stdin); 64 n=read(),m=read();--n;ll x,y,g; 65 while(m--){ 66 char op=getop();int l=read(),r=read();--r; 67 if(op==C) x=read(),update(1,1,n,l,r,x); 68 else{ 69 y=1ll*(r-l+2)*(r-l+1)>>1; 70 x=query(1,1,n,l,r,0)*(r+1)*(1-l)+query(1,1,n,l,r,1)*(l+r)-query(1,1,n,l,r,2); 71 g=gcd(x,y);print(x/g),sr[C]=/,print(y/g); 72 } 73 } 74 return Ot(),0; 75 }

洛谷P2221 [HAOI2012]高速公路(線段樹+概率期望)