luogu P3567 [POI2014] Couriers
给一个数列,每次询问一个区间内有没有一个数出现次数超过一半
区间的一半就是(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 }
> 别忘了 总有人在等着你