P3567 [POI 2014] KUR-Couriers
题目链接
题意:
给一个数列,每次询问一个区间内有没有一个数出现次数超过一半。
思路:
首先,如果一个区间内有一个数出现次数超过了一半,那么它一定是中位数。所以我们只需找到这个区间的中位数,然后判断这个数字出现的次数是否超过一半即可。实现的话用主席树寻找一个区间的中位数,判断次数可以用二分查找。具体实现见代码。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int N = 5e5+5;
#define lc(x) tr[x].l
#define rc(x) tr[x].r
struct Tree{
int l,r,s;
}tr[N*23]; //N*(logN+3)
int root[N],idx;
int arr[N];
vector<int> b;
void build(int &x,int l,int r){
x=++idx;
if(l==r) return ;
int mid=l+r>>1;
build(lc(x),l,mid);
build(rc(x),mid+1,r);
}
void insert(int x,int &y,int l,int r,int k){
y=++idx; tr[y]=tr[x]; tr[y].s++;
if(l==r) return ;
int mid=l+r>>1;
if(k<=mid) insert(lc(x),lc(y),l,mid,k);
else insert(rc(x),rc(y),mid+1,r,k);
}
int query(int x,int y,int l,int r,int k){
if(l==r) return l;
int mid=l+r>>1;
int s=tr[lc(y)].s-tr[lc(x)].s;
if(k<=s) return query(lc(x),lc(y),l,mid,k);
else return query(rc(x),rc(y),mid+1,r,k-s);
}
map<int,vector<int>>mp;
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int n,q;
cin>>n>>q;
for(int i=1;i<=n;++i){
cin>>arr[i];
mp[arr[i]].push_back(i);
b.push_back(arr[i]);
}
sort(b.begin(),b.end());
b.erase(unique(b.begin(),b.end()),b.end());
int bn=b.size();
build(root[0],1,bn);
for(int i=1;i<=n;++i){
int id=lower_bound(b.begin(),b.end(),arr[i])-b.begin()+1;
insert(root[i-1],root[i],1,bn,id);
}
while(q--){
int l,r;
cin>>l>>r;
int len=r-l+1;
int k=(len>>1)+1;
int id=query(root[l-1],root[r],1,bn,k)-1;
int x=b[id];
auto it=lower_bound(mp[x].begin(),mp[x].end(),l);
auto it1=upper_bound(mp[x].begin(),mp[x].end(),r);
if(it==it1){
cout<<0<<endl;
continue;
}
it1--;
int c=it1-it+1;
if(c>(double)(len/2.0)){
cout<<x<<endl;
}else{
cout<<0<<endl;
}
}
return 0;
}

浙公网安备 33010602011771号