【主席树】bzoj3524: [Poi2014]Couriers
主席树 上 二分(和线段树上二分一个道理的单支log
Description
给一个长度为n的序列a。1≤a[i]≤n。
m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。
Input
第一行两个数n,m。
第二行n个数,a[i]。
接下来m行,每行两个数l,r,表示询问[l,r]这个区间。
Output
m行,每行对应一个答案。
题目分析
线段树 上 二分的一个简单应用。
有些时候就是把套二分做成上二分,少一只log
1 #include<bits/stdc++.h> 2 const int maxn = 500035; 3 const int maxNode = 12000035; 4 5 struct node 6 { 7 int val,l,r; 8 }a[maxNode]; 9 int n,m,tot,rt[maxn],w[maxn],cnt[maxn]; 10 11 int read() 12 { 13 char ch = getchar(); 14 int num = 0, fl = 1; 15 for (; !isdigit(ch); ch=getchar()) 16 if (ch=='-') fl = -1; 17 for (; isdigit(ch); ch=getchar()) 18 num = (num<<1)+(num<<3)+ch-48; 19 return num*fl; 20 } 21 void build(int &rt, int l, int r) 22 { 23 rt = ++tot; 24 if (l==r) return; 25 int mid = (l+r)>>1; 26 build(a[rt].l, l, mid); 27 build(a[rt].r, mid+1, r); 28 } 29 void update(int pre, int &rt, int l, int r, int c) 30 { 31 rt = ++tot, a[rt] = a[pre], ++a[rt].val; 32 if (l==r) return; 33 int mid = (l+r)>>1; 34 if (c <= mid) update(a[pre].l, a[rt].l, l, mid, c); 35 else update(a[pre].r, a[rt].r, mid+1, r, c); 36 } 37 int query(int L, int R) 38 { 39 int l = 1, r = cnt[0], x = rt[L-1], y = rt[R], lim = (R-L+1)>>1, mid; 40 while (l!=r) 41 { 42 mid = (l+r)>>1; 43 if (a[y].val-a[x].val <= lim) return 0; 44 if (a[a[y].l].val-a[a[x].l].val > lim) 45 r = mid, x = a[x].l, y = a[y].l; 46 else if (a[a[y].r].val-a[a[x].r].val > lim) 47 l = mid+1, x = a[x].r, y = a[y].r; 48 else return 0; 49 } 50 return cnt[l]; 51 } 52 void write(int x){if (x/10) write(x/10);putchar(x%10+'0');} 53 int main() 54 { 55 n = read(), m = read(); 56 for (int i=1; i<=n; i++) cnt[i] = w[i] = read(); 57 std::sort(cnt+1, cnt+n+1); 58 cnt[0] = std::unique(cnt+1, cnt+n+1)-cnt-1; 59 build(rt[0], 1, n); 60 for (int i=1; i<=n; i++) 61 { 62 w[i] = std::lower_bound(cnt+1, cnt+cnt[0]+1, w[i])-cnt; 63 update(rt[i-1], rt[i], 1, cnt[0], w[i]); 64 } 65 for (int i=1; i<=m; i++) 66 { 67 int l = read(), r = read(); 68 write(query(l, r)), putchar('\n'); 69 } 70 return 0; 71 }
END