bzoj 3524 主席树 解题报告

来源:互联网 发布:手机mac修改器怎么用 编辑:程序博客网 时间:2024/06/06 09:38

Description

给一个长度为n的序列a。1≤a[i]≤n。
m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。

Input

第一行两个数n,m。
第二行n个数,a[i]。
接下来m行,每行两个数l,r,表示询问[l,r]这个区间。

Output

m行,每行对应一个答案。

Sample Input

7 5
1 1 3 2 3 4 3
1 3
1 4
3 7
1 7
6 6

Sample Output

1
0
3
0
4

HINT

【数据范围】

n,m≤500000

Source

By Dzy

思路

又有m组询问,每次对于一个区间[l,r]问是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2。如果存在,输出这个数,否则输出0。
主席树

代码

!!!!!我没权限

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<queue>using namespace std;const int N=500005;int n,m,l,r,x,cnt,rt[N],son[2][N*20],sum[N*20];void Insert(int rl,int rn,int l,int r,int v){    sum[rn]=sum[rl]+1;    if(l==r)return;    int mid = (l+r)/2;    if(mid>=v)     {        son[1][rn]=son[1][rl];        son[0][rn]=++cnt;        Insert(son[0][rl],son[0][rn],l,mid,v);    }    else     {        son[0][rn]=son[0][rl];        son[1][rn]=++cnt;        Insert(son[1][rl],son[1][rn],mid+1,r,v);    }}int query(int rl,int rn,int l,int r,int k){    if(l==r)return l;    int mid=(l+r)/2;    if(sum[son[0][rn]]-sum[son[0][rl]]>k)     return query(son[0][rl],son[0][rn],l,mid,k);    if(sum[son[1][rn]]-sum[son[1][rl]]>k)     return query(son[1][rl],son[1][rn],mid+1,r,k);    return 0;}int main(void){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)    rt[i]=++cnt;    for(int i=1;i<=n;i++)    {        scanf("%d",&x);        Insert(rt[i-1],rt[i],1,n,x);    }    for(int i=1;i<=m;i++)    {        scanf("%d%d",&l,&r);        printf("%d\n",query(rt[l-1],rt[r],1,n,(r-l+1)/2));    }    return 0;}
原创粉丝点击