BZOJ 3524: [Poi2014]Couriers 主席树

   这道题直接在我上一篇博客的代码的基础上改的。再一次地证明了 read() 读入是要比 scanf 快的事实,没加read(),跑了5400毫秒,加了之后,跑了4600毫秒,再加个 inline 又快了300毫秒。 最终4384毫秒跑完此题。加油。 (不过一开始因为是改的,RE了一次,以后要小心啊!)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #define rep(i,j,k) for(int i = j; i <= k; i++)
 5 using namespace std;
 6 int root[500005], a[500005], p[500005];
 7 int n_nodes = 0, n_numb;
 8 
 9 inline int read()
10 {
11     int s = 0, t = 1; char c = getchar();
12     while( !isdigit(c) ){
13         if( c == '-' ) t = -1; c = getchar();
14     }
15     while( isdigit(c) ){
16         s = s * 10 + c - '0'; c = getchar();
17     }
18     return s * t;
19 }
20 
21 struct node{
22 int times, lc, rc;
23 } nod[10000000];
24 
25 void build(int l,int r,int&p){
26     p = ++n_nodes;
27     nod[p].lc = nod[p].rc = nod[p].times = 0;
28     if( l >= r ) return;
29     int mid = (l+r)/2;
30     build(l,mid,nod[p].lc); build(mid+1,r,nod[p].rc);
31 }
32 
33 void build2(int l,int r,int&p, int pre,int mre)
34 {
35     p = ++n_nodes;
36     nod[p] = nod[pre];
37     nod[p].times++;
38     if( l >= r ) return;
39     int mid = (l+r)/2;
40     if( mre <= mid ){
41         build2(l,mid,nod[p].lc,nod[pre].lc,mre);
42     }    
43     else {
44         build2(mid+1,r,nod[p].rc,nod[pre].rc,mre);
45     }
46 }
47 
48 int ask(int l,int r,int pre,int p,int k)
49 {
50     if( nod[p].times - nod[pre].times <= k ) return -1;
51     if( l >= r ) return l;
52     int sl = nod[nod[p].lc].times - nod[nod[pre].lc].times;
53     int mid = (l+r) / 2;
54     if( sl > k ){
55         return ask(l,mid,nod[pre].lc,nod[p].lc,k);
56     }
57     else{
58         return ask(mid+1,r,nod[pre].rc,nod[p].rc,k);
59     }
60 }
61 
62 int main()
63 {
64     int n = read(), q = read();
65     rep(i,1,n){
66         p[i] = a[i] = read();
67     }
68     sort(p+1,p+1+n);
69     n_numb = unique(p+1,p+1+n) - p - 1;
70     build(1,n_numb,root[0]);
71     rep(i,1,n){
72         int m = lower_bound(p+1,p+n_numb+1,a[i]) - p;
73         build2(1,n_numb,root[i],root[i-1],m);
74     }
75     rep(i,1,q){
76         int x = read(), y = read();
77         int k = (y-x+1)/2;
78         int m = ask(1,n_numb,root[x-1],root[y],k);
79         if( m == -1 ) printf("%d\n", 0);
80         else printf("%d\n", p[m]);
81     }
82     return 0;
83 }

 

这是指针版的,又快了100多毫秒(指针要传引用的)

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 #define rep(i,j,k) for(int i = j; i <= k; i++)
 5 using namespace std;
 6 int a[500005], p[500005];
 7 int n_nodes = 0, n_numb;
 8  
 9 inline int read()
10 {
11     int s = 0, t = 1; char c = getchar();
12     while( !isdigit(c) ){
13         if( c == '-' ) t = -1; c = getchar();
14     }
15     while( isdigit(c) ){
16         s = s * 10 + c - '0'; c = getchar();
17     }
18     return s * t;
19 }
20  
21 struct node{
22 int times;
23 node* lc, *rc;
24 } nod[10000000];
25 node* root[500005], *pt;
26 
27 void build(int l,int r,node*&p){
28     p = ++pt;
29     p->lc = p->rc = NULL; pt->times = 0;
30     if( l >= r ) return;
31     int mid = (l+r)/2;
32     build(l,mid,p->lc); build(mid+1,r,p->rc);
33 }
34  
35 void build2(int l,int r,node*&p, node*pre,int mre)
36 {
37     p = ++pt; 
38     *p = *pre; p->times++;
39     if( l >= r ) return;
40     int mid = (l+r)/2;
41     if( mre <= mid ){
42         build2(l,mid,p->lc,pre->lc,mre);
43     }   
44     else {
45         build2(mid+1,r,p->rc,pre->rc,mre);
46     }
47 }
48  
49 int ask(int l,int r,node* pre,node* p,int k)
50 {
51     if( p->times - pre->times <= k ) return -1;
52     if( l >= r ) return l;
53     int sl = p->lc->times - pre->lc->times;
54     int mid = (l+r) / 2;
55     if( sl > k ){
56         return ask(l,mid,pre->lc,p->lc,k);
57     }
58     else{
59         return ask(mid+1,r,pre->rc,p->rc,k);
60     }
61 }
62  
63 int main()
64 {
65     int n = read(), q = read(); pt = nod;
66     rep(i,1,n){
67         p[i] = a[i] = read();
68     }
69     sort(p+1,p+1+n);
70     n_numb = unique(p+1,p+1+n) - p - 1;
71     build(1,n_numb,root[0]);
72     rep(i,1,n){
73         int m = lower_bound(p+1,p+n_numb+1,a[i]) - p;
74         build2(1,n_numb,root[i],root[i-1],m);
75     }
76     rep(i,1,q){
77         int x = read(), y = read();
78         int k = (y-x+1)/2;
79         int m = ask(1,n_numb,root[x-1],root[y],k);
80         if( m == -1 ) printf("%d\n", 0);
81         else printf("%d\n", p[m]);
82     }
83     return 0;
84 }

 

3524: [Poi2014]Couriers

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 1004  Solved: 350
[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行,每行两个数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

 

posted on 2015-12-29 14:24  83131  阅读(140)  评论(0编辑  收藏  举报

导航