【主席树】BZOJ3524-[Poi2014]Couriers

【题目大意】

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

【思路】

只有query部分需要稍作修改。由于每个节点代表的是一个大小区间数的总数,所以只需判断左右子数的sum值是否大于(r-l+1)/2,满足继续往左右子树查询。没有满足条件的就返回0。由于当前的节点的sum值一定是大于(r-l+1)/2的,如果l==r直接返回l即可。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<vector>
 6 #define lson l,m
 7 #define rson m+1,r
 8 using namespace std;
 9 const int MAXN=500000+50;
10 int n,m,d,a[MAXN],hash[MAXN],tot;
11 int T[MAXN],L[MAXN<<5],R[MAXN<<5],sum[MAXN<<5];
12
13 int build(int l,int r)
14 {
15     int rt=++tot;
16     sum[rt]=0;
17     if (l!=r)
18     {
19         int m=(l+r)>>1;
20         L[rt]=build(lson);
21         R[rt]=build(rson);
22     }
23     return rt;
24 }
25
26 int update(int pre,int l,int r,int x)
27 {
28     int rt=++tot;
29     L[rt]=L[pre],R[rt]=R[pre],sum[rt]=sum[pre]+1;
30     if (l!=r)
31     {
32         int m=(l+r)>>1;
33         if (x<=m) L[rt]=update(L[pre],lson,x);
34             else R[rt]=update(R[pre],rson,x);
35     }
36     return rt;
37 }
38
39 int query(int lrt,int rrt,int l,int r,int k)
40 {
41     if (l==r) return l;
42     int m=(l+r)>>1;
43     if (sum[L[rrt]]-sum[L[lrt]]>k) return query(L[lrt],L[rrt],lson,k);
44     if (sum[R[rrt]]-sum[R[lrt]]>k) return query(R[lrt],R[rrt],rson,k);
45     return 0;
46 }
47
48 void init()
49 {
50     scanf("%d%d",&n,&m);
51     for (int i=1;i<=n;i++) scanf("%d",&a[i]),hash[i]=a[i];
52     sort(hash+1,hash+n+1);
53     d=unique(hash+1,hash+n+1)-(hash+1);
54
55     tot=0;
56     T[0]=build(1,d);
57     for (int i=1;i<=n;i++)
58     {
59         int x=lower_bound(hash+1,hash+d+1,a[i])-hash;
60         //注意离散化之后是从1开始,所以减去的是hash而不是hash+1
61         T[i]=update(T[i-1],1,d,x);
62     }
63 }
64
65 void solve()
66 {
67     for (int i=0;i<m;i++)
68     {
69         int l,r;
70         scanf("%d%d",&l,&r);
71         int ans=query(T[l-1],T[r],1,d,(r-l+1)>>1);
72         printf("%d\n",hash[ans]);
73     }
74 }
75
76 int main()
77 {
78     init();
79     solve();
80     return 0;
81 } 
时间: 2024-07-31 14:30:41

【主席树】BZOJ3524-[Poi2014]Couriers的相关文章

[BZOJ2223][BZOJ3524][Poi2014]Couriers 主席树

3524: [Poi2014]Couriers Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 2436  Solved: 960[Submit][Status][Discuss] Description 给一个长度为n的序列a.1≤a[i]≤n.m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2.如果存在,输出这个数,否则输出0. Input 第一行两个数n,m.第二行n个数,a[i].接下来m行,

bzoj3524 [Poi2014]Couriers/2223 [Coci 2009]PATULJCI

题目链接1 题目链接2 主席树模板题 两题有细节不同 1 #include<algorithm> 2 #include<iostream> 3 #include<cstdlib> 4 #include<cstring> 5 #include<cstdio> 6 #include<string> 7 #include<cmath> 8 #include<ctime> 9 #include<queue>

BZOJ3524 [Poi2014]Couriers

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3524 题目大意:给一个长度为n的序列a.1≤a[i]≤n. m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2.如果存在,输出这个数,否则输出0. 题解:感觉这种题,随便搞啊,莫队什么的,主席树也可以啊,就当复习主席树咯 代码: 1 #include<iostream> 2 #include<algorithm> 3 #incl

[Poi2014]Couriers

bzoj3524: [Poi2014]Couriers 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

[bzoj3524][Poi2014]Couriers_主席树

Couriers bzoj-3524 Poi-2014 题目大意:给定n个数的序列,询问区间内是否存在一个在区间内至少出现了(区间长度>>1)次的数.如果有,输出该数,反之输出0. 注释:$1\le n,m\le 5\cdot 10^5$. 想法:主席树裸题. 主流做法就是弄一个Existence数组询问有没有这样的数,然后查询区间中位数即可. 但是可以在query的时候强行查询,因为没有输出0,直接输出即可. 最后,附上丑陋的代码... ... #include <iostream&g

BZOJ 3524: [Poi2014]Couriers( 主席树 )

卡我空间.... 这道题应该是主席树入门题...无修改 , 离散化都不用...出题人业界良心啊 一开始的空白树我 build 出来结果就多了整整 2n 个 Node , 然后就 MLE 了... ( 双倍经验 , 另一道见上图 ) ---------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring&g

3524: [Poi2014]Couriers -- 主席树

3524: [Poi2014]Couriers Time Limit: 20 Sec  Memory Limit: 256 MB 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

主席树 Couriers

[bzoj3524/2223][Poi2014]Couriers 2014年4月19日1,2571 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行,每行对应一个答案./* #include<iostream>

【bzoj3524】[Poi2014]Couriers

题目描述 给一个长度为n的序列a.1≤a[i]≤n.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 题解 主席树 同bzoj2223,也不需要离散化. b