BZOJ 3542 [Poi2014]Couriers ——可持久化线段树
【题目分析】
查找区间内出现次数大于一半的数字。
直接用主席树,线段树上维护区间大小,由于要求出现次数大于一半,每到一个节点可以分治下去。
时间复杂度(N+Q)logN
【代码】
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <string> #include <algorithm> #include <vector> #include <iostream> #include <queue> using namespace std; #define maxn 500005 #define mlog 30 #define inf (0x3f3f3f3f) int read() { int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } int rt[maxn],ls[maxn*mlog],rs[maxn*mlog],siz[maxn*mlog],idx=0; int n,m,x,a[maxn]; int ins(int o,int l,int r,int x) { int k=++idx; siz[k]=siz[o]+1; int mid=(l+r)/2; if (l==r) return k; if (x<=mid) rs[k]=rs[o],ls[k]=ins(ls[o],l,mid,x); else ls[k]=ls[o],rs[k]=ins(rs[o],mid+1,r,x); return k; } int query(int o1,int o2,int l,int r,int tim) { // printf("%d %d\n",l,r); if (l==r) { if (siz[o2]-siz[o1]>tim) return l; else return 0; } if (siz[ls[o2]]-siz[ls[o1]]>siz[rs[o2]]-siz[rs[o1]]) return query(ls[o1],ls[o2],l,(l+r)/2,tim); else return query(rs[o1],rs[o2],(l+r)/2+1,r,tim); } int main() { n=read();m=read(); for (int i=1;i<=n;++i) a[i]=x=read(),rt[i]=ins(rt[i-1],1,n,x); // for (int i=1;i<=n;++i) printf("%d ",a[i]); printf("\n"); for (int i=1;i<=m;++i) { int l=read(),r=read(); // printf("ask for %d to %d\n",l,r); if (l==r) { // printf("l == r\n"); printf("%d\n",a[r]); } else printf("%d\n",query(rt[l-1],rt[r],1,n,(r-l+1)/2)); } }