1. 程式人生 > >luogu P3567 [POI2014] Couriers

luogu P3567 [POI2014] Couriers

|| https 每次 離散 == n) tchar 有一個 http

傳送門

給一個數列,每次詢問一個區間內有沒有一個數出現次數超過一半

區間的一半就是(r-l+1)/2

對於主席樹中的兩棵樹L,R中的同一個節點[l,r] 如果sum的差值大於k

說明在原序列下標L`R的區間中出現了多於k個權值處於[l,r]的數字

所以按照這個套路二分就行

然後這題bzoj有雙倍經驗 這裏粘的這道題要離散就這個了

Code:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<vector>
 5 #include<algorithm>
 6
#define rep(i,a,n) for(int i = a;i <= n;i++) 7 #define per(i,n,a) for(int i = n;i >= a;i--) 8 using namespace std; 9 typedef long long ll; 10 int read() { 11 int as = 0,fu = 1; 12 char c = getchar(); 13 while(c < 0 || c > 9) { 14 if(c == -) fu = -1; 15 c = getchar();
16 } 17 while(c >= 0 && c <= 9) { 18 as = as * 10 + c - 0; 19 c = getchar(); 20 } 21 return as * fu; 22 } 23 //head 24 const int N = 500005; 25 const int M = 10000005; 26 #define int ll 27 int n,Q,T,tot; 28 int a[N],b[N]; 29 int rt[N],ls[M],rs[M],sum[M]; 30 void ins(int
l,int r,int &t,int pre,int q) { 31 t = ++tot,ls[t] = ls[pre],rs[t] = rs[pre]; 32 sum[t] = sum[pre] + 1; 33 if(l == r) return; 34 int m = l+r >> 1; 35 if(q <= m) ins(l,m,ls[t],ls[pre],q); 36 else ins(m+1,r,rs[t],rs[pre],q); 37 } 38 39 int query(int l,int r,int t,int pre,int k) { 40 if(l == r) return l; 41 int m = l+r >> 1; 42 int tmp1 = sum[ls[t]] - sum[ls[pre]]; 43 int tmp2 = sum[rs[t]] - sum[rs[pre]]; 44 if(k < tmp1) return query(l,m,ls[t],ls[pre],k); 45 if(k < tmp2) return query(m+1,r,rs[t],rs[pre],k); 46 return 0; 47 } 48 #undef int 49 50 int main() { 51 n = read(),Q = read(); 52 rep(i,1,n) a[i] = b[i] = read(); 53 sort(b+1,b+n+1),T = unique(b+1,b+n+1) - (b+1); 54 rep(i,1,n) ins(1,T,rt[i],rt[i-1],lower_bound(b+1,b+T+1,a[i]) - b); 55 rep(i,1,Q) { 56 ll l = read(),r = read(); 57 printf("%lld\n",b[query(1,T,rt[r],rt[l-1],r-l+1 >> 1)]); 58 } 59 return 0; 60 }

luogu P3567 [POI2014] Couriers