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 MBSubmit: 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
1 1 3 2 3 4 3
1 3
1 4
3 7
1 7
6 6
Sample Output
1
0
3
0
4
0
3
0
4
HINT
【数据范围】
n,m≤500000
————————————————