值域线段树 bzoj 4627

     这是题目链接4627: [BeiJing2016]回转寿司

题目大意:

给定n个数,求有多少个字段和在 满足 L<=sum<=R;

解题思路

需要解这个题目,需要有线段树加可持续化的思想,但是这个题目只需要上一棵线段树的信息,所以可以不用主席树,只要用到值域线段树。那么,这样就可以把问题转化为:

先处理处前缀和。 求 L<=sum[j]-sum[i]<=R (0 <=i < j<=n) 有多少个?

那么我们可以用值域线段树搞一下,线段树节点存值的个数,每次把前缀和这个值插入,每次查询,原问题就等同于 当前线段树中有多少个值是在 [ sum[j]-R , sum[j]-L ] 这个区间,

意思就是,每次把上一个前缀和插入需要计算一下上一棵线段树值在[ sum[j]-R , sum[j]-L ] 个数。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <vector>
 5 #include <iostream>
 6 using namespace std;
 7 
 8 typedef long long int LL;
 9 const LL INF=10000000000ll;
10 const int maxn=100000*32;
11 struct ACM
12 {
13     struct Node
14     {
15         LL val;
16         int lson,rson;
17     }seg[maxn];
18     int sz;
19     int newnode()
20     {
21         sz++;
22         seg[sz].val=0;
23         seg[sz].rson=-1;
24         seg[sz].lson=-1;
25         return sz;
26     }
27     void init()
28     {
29         sz=-1;
30     }
31     void update(int &root,LL l,LL r,LL val)
32     {
33         if(root==-1) root=newnode();
34         seg[root].val++;
35         if(l==r) return ;
36         LL mid=(l+r)>>1;
37         if(val<=mid) update(seg[root].lson,l,mid,val);
38         else update(seg[root].rson,mid+1,r,val);
39     }
40     LL query(int root,LL l,LL r,LL ql,LL qr)
41     {
42         if(root==-1) return 0;
43         if(l==ql&&r==qr) return seg[root].val;
44         LL mid=(l+r)>>1;
45         if(qr<=mid) return query(seg[root].lson,l,mid,ql,qr);
46         else if(ql>mid) return query(seg[root].rson,mid+1,r,ql,qr);
47         else return query(seg[root].lson,l,mid,ql,mid)+query(seg[root].rson,mid+1,r,mid+1,qr);
48     }
49     /**
50     void debug(int i)
51     {
52         if(i==-1) return ;
53         printf("node=%d val=%lld lson=%d rson=%d
",i,seg[i].val,seg[i].lson,seg[i].rson);
54         debug(seg[i].lson),debug(seg[i].rson);
55     }
56     */
57 }AC;
58 
59 int main()
60 {
61     int n,L,R,root=-1;
62     scanf("%d%d%d",&n,&L,&R);
63     LL sum=0,ans=0;
64     AC.init();
65     for(int i=1; i<=n; i++)
66     {
67         int num;
68         scanf("%d",&num);
69         AC.update(root,-INF,INF,sum);
70         sum+=num;
71         ans+=AC.query(root,-INF,INF,sum-R,sum-L);
72     }
73     printf("%lld
",ans);
74     return 0;
75 }
原文地址:https://www.cnblogs.com/coded-ream/p/7207923.html