#2614[Poi2014]Couriers
主席树模板题
题面
给一个长度为n的序列a。1≤a[i]≤n。
【数据范围】
n,m≤500000
m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。
输入
第一行两个数n,m。 第二行n个数,a[i]。 接下来m行,每行两个数l,r,表示询问[l,r]这个区间。
输出
m行,每行对应一个答案。
样例输入
7 5
1 1 3 2 3 4 3
1 3
1 4
3 7
1 7
6 6
样例输出
1
0
3
0
4
SOL
很容易想到用主席树来切这道题
题目的意思有点像找第k大数,与woj #1903略有区别的是,她要求你找出区间[L,R]中出现次数超过(r-l+1)/2的数——其实她的要求也就是让你找到[L,R]中的一个出现次数超过len(l,r)/2的数,那么也就意味着,你最多在这个区间找到一个合法的数。
这听起来像是一句废话,但是这句话让这道题变得很简单——就是找第k大,只不过k=len(l,r)/2+1而已。
代码:
#include<bits/stdc++.h>
#define limit ((v-u+1)>>1)
#define N 500505
int n,m;
using namespace std;
inline int rd(){
int w=1,data=0;static char ch='0';
ch=getchar();
while((ch!='-')&&(!isdigit(ch)))ch=getchar();
if(ch=='-')w=-1,ch=getchar();
while(isdigit(ch))data=(data<<1)+(data<<3)+ch-'0',ch=getchar();
return data*w;
}
inline void write(int x){
if(x<0){putchar('-');x=-x;}
if(x>9)write(x/10);
putchar(x%10+'0');
}
int tot,a[N],h[N],rt[N<<5];
struct tree{
int l,r,sum;
}t[N<<5];
inline int build(int l,int r){
++tot;int root=tot;t[root].sum=0;
if(l<r){
int mid=l+r>>1;
t[root].l=build(l,mid);
t[root].r=build(mid+1,r);
}
return root;
}
inline int update(int p,int ql,int qr,int pre){
++tot;int root=tot;
t[root].l=t[pre].l,t[root].r=t[pre].r,t[root].sum=t[pre].sum+1;
if(ql==qr)return root;
int mid=ql+qr>>1;
if(p<=mid)t[root].l=update(p,ql,mid,t[pre].l);
else t[root].r=update(p,mid+1,qr,t[pre].r);
return root;
}
inline int query(int ql,int qr,int u,int v,int k){
if(ql==qr)return ql;
int mid=ql+qr>>1;
int num1=t[t[v].l].sum-t[t[u].l].sum,num2=t[t[v].r].sum-t[t[u].r].sum;
if(num1>k)return query(ql,mid,t[u].l,t[v].l,k);
else if(num2>k)return query(mid+1,qr,t[u].r,t[v].r,k);else return 0;
}
int main(){
n=rd();m=rd();
for(int register i=1;i<=n;i++){
a[i]=rd();
h[i]=a[i];
}
sort(h+1,h+n+1);
int nn=unique(h+1,h+n+1)-h-1;
rt[0]=build(1,nn);
for(int register i=1;i<=n;i++){
int pos=lower_bound(h+1,h+nn+1,a[i])-h;
rt[i]=update(pos,1,nn,rt[i-1]);
}h[0]=0;
while(m--){
int u=rd(),v=rd();int ans=query(1,nn,rt[u-1],rt[v],limit);
write(h[ans]);putchar('\n');
}return 0;
}
//码风略丑,还望神仙们见谅!!!