1. 程式人生 > >初涉值域線段樹

初涉值域線段樹

its isdigit ret i++ 點線 num per sdi ans

其實就是線段樹啦

什麽是值域線段樹

我們(初學者)都知道線段樹是拿來維護數列區間的信息的。但是如果我們想要查詢的重點在於數值而不是區間信息呢?這時候就要對於值域區間維護線段樹了。

例題

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

初涉值域線段樹