题目链接:https://cn.vjudge.net/contest/281960#problem/F
题目大意:中文题目
具体思路:权值线段树,我们每次寻找的是满足 (i<j) L<=s[i]-s[j]<=R.转换一下,就是 s[j]-R<=s[i]<=s[j]-L。这样的话,我们每一次寻找满足情况的合数就可以了。
ps:第一次做权值线段树,感觉这东西和线段树差不多,只不过每一个区间表示成了具体的值有多少个。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 # define ll long long 4 # define inf 10000000000ll 5 # define lson l,m,rt<<1 6 # define rson m+1,r,rt<<1|1 7 const int maxn = 8e6+5; 8 int son[maxn][2]; 9 ll siz[maxn]; 10 int tot,rt; 11 void update(int &x,ll l,ll r,ll val) 12 { 13 if(!x)// 如果这一段区间之前没有过,编号 14 x=++tot; 15 siz[x]++; 16 if(l==r) 17 return ; 18 ll m=(l+r)>>1; 19 if(val<=m) 20 update(son[x][0],l,m,val); 21 else if(val>m) 22 update(son[x][1],m+1,r,val); 23 } 24 ll query(int x,ll l,ll r,ll L,ll R) 25 { 26 if(!x) 27 return 0; 28 if(l==L&&R==r)//查询的时候注意,如果查询到底的话,会超时 29 { 30 return siz[x]; 31 } 32 ll m=(l+r)>>1; 33 if(R<=m) 34 return query(son[x][0],l,m,L,R); 35 else if(L>m) 36 return query(son[x][1],m+1,r,L,R); 37 else 38 return query(son[x][0],l,m,L,m)+query(son[x][1],m+1,r,m+1,R); 39 } 40 int main() 41 { 42 int n,l,r; 43 scanf("%d %d %d",&n,&l,&r); 44 ll tmp=0,sum=0,ans=0; 45 for(int i=1; i<=n; i++) 46 { 47 update(rt,-inf,inf,sum); 48 scanf("%lld",&tmp); 49 sum+=tmp; 50 ans+=query(rt,-inf,inf,max(-inf,sum-r),min(sum-l,inf)); 51 // cout<<tmp<<endl; 52 } 53 printf("%lld ",ans); 54 return 0; 55 }