F - 回转寿司 (权值线段树)

题目链接: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\n",ans);
54     return 0;
55 }

猜你喜欢

转载自www.cnblogs.com/letlifestop/p/10355510.html