初涉值域线段树

其实就是线段树啦

什么是值域线段树

我们(初学者)都知道线段树是拿来维护数列区间的信息的。但是如果我们想要查询的重点在于数值而不是区间信息呢?这时候就要对于值域区间维护线段树了。

例题

bzoj4627: [BeiJing2016]回转寿司

题目大意

给定$n$个数和$L,R$,问其中区间和满足$L<=sum[r]-sum[l-1]<=R$的区间有多少

N≤100000,|Ai|≤100000,0≤L, R≤10^9

题目分析

值域线段树中每个节点代表一个值的区间,其实和基础的线段树差不多。

还有这题由于LR很大,并且没办法离散化,所以还要动态开点线段树。

hint:注意一下数组的范围。

 1 #include<bits/stdc++.h>
 2 typedef long long ll;
 3 const ll INF = 1e10;
 4 const int maxn = 6000035;
 5 
 6 struct node
 7 {
 8     int d[2];
 9     ll val;
10     int &operator [](int a)
11     {
12         return d[a];
13     }
14 }a[maxn];
15 int n,l,r,root,tot;
16 ll s[maxn],ans;
17 
18 int read()
19 {
20     char ch = getchar();
21     int num = 0;
22     bool fl = 0;
23     for (; !isdigit(ch); ch = getchar())
24         if (ch=='-') fl = 1;
25     for (; isdigit(ch); ch = getchar())
26         num = (num<<1)+(num<<3)+ch-48;
27     if (fl) num = -num;
28     return num;
29 }
30 void update(int &x, ll L, ll R, ll c)
31 {
32     if (!x){
33         x = ++tot;
34         a[x][0] = a[x][1] = a[x].val = 0;
35     }
36     a[x].val++;
37     if (L==R) return;
38     ll mid = (L+R)>>1;
39     if (mid >= c)
40         update(a[x][0], L, mid, c); 
41     else update(a[x][1], mid+1, R, c);
42 }
43 ll query(int x, ll L, ll R, ll l, ll r)
44 {
45     if (L <= l&&r <= R) return a[x].val;
46     ll mid = (l+r)>>1, ret = 0;
47     if (L <= mid && a[x][0]) ret += query(a[x][0], L, R, l, mid);
48     if (R > mid && a[x][1]) ret += query(a[x][1], L, R, mid+1, r);
49     return ret;
50 }
51 int main()
52 {
53     n = read(), l = read(), r = read();
54     for (int i=1; i<=n; i++)
55         s[i] = s[i-1]+read();
56     update(root, -INF, INF, 0);
57     for (int i=1; i<=n; i++)
58     {
59         ans += query(root, s[i]-r, s[i]-l, -INF, INF);
60         update(root, -INF, INF, s[i]);
61     }
62     printf("%lld\n",ans);
63     return 0;
64 } 

 

 

END

posted @ 2018-06-07 20:58  AntiQuality  阅读(894)  评论(0编辑  收藏  举报