1. 程式人生 > >[BZOJ4627][BeiJing2016]回轉壽司(線段樹)

[BZOJ4627][BeiJing2016]回轉壽司(線段樹)

從左到右處理,設到當前數R的字首和為cnt[i],則以i為右端點的合法的區間左端點j必然是L<=cnt[i]-cnt[j-1]<=R,即cnt[i]-R<=cnt[j-1]<=cnt[i]-L。

問題相當於每次單點在cnt[i]處計數器加1,然後區間詢問[cnt[i]-R,cnt[i]-L]中的數之和,動態開點線段樹即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #define
lson ls[x],L,mid 6 #define rson rs[x],mid+1,R 7 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 8 typedef long long ll; 9 using namespace std; 10 11 const int N=5000100; 12 const ll inf=1e12; 13 ll cnt,res,ans,n,rt,lp,rp,nd,x,sm[N],ls[N],rs[N]; 14 15 void mdf(ll &x,ll L,ll R,ll pos){
16 if (!x) x=++nd; 17 if (L==R){ sm[x]++; return; } 18 ll mid=(L+R)>>1; 19 if (pos<=mid) mdf(lson,pos); else mdf(rson,pos); 20 sm[x]=sm[ls[x]]+sm[rs[x]]; 21 } 22 23 ll que(ll x,ll L,ll R,ll l,ll r){ 24 if (!x) return 0; 25 if (L==l && r==R) return
sm[x]; 26 ll mid=(L+R)>>1; 27 if (r<=mid) return que(lson,l,r); 28 else if (l>mid) return que(rson,l,r); 29 else return que(lson,l,mid)+que(rson,mid+1,r); 30 } 31 32 int main(){ 33 freopen("bzoj4627.in","r",stdin); 34 freopen("bzoj4627.out","w",stdout); 35 scanf("%lld%lld%lld",&n,&lp,&rp); mdf(rt,-inf,inf,0); 36 rep(i,1,n){ 37 scanf("%lld",&x); cnt+=x; ll res=que(rt,-inf,inf,cnt-rp,cnt-lp); 38 ans+=res; mdf(rt,-inf,inf,cnt); 39 } 40 printf("%lld\n",ans); 41 return 0; 42 }