这题开始的思路就是模拟:就像数组中插点一样,每一个想买票的人都想往前插队!
但是这样的话肯定TLE, 看了别人的思路之后才恍然大悟!
正解:
将开始的正序插入,变成倒序插入,这样的话,想一想:第 i 个人想要插在 p[i]
的位置上,那么就要保证所插入的位置之前一定要有 p[i]-1个空位!因为一定会有p[j]<p[i]
(0<=p[j]<=j,每个人都想往前插队)
的第j个人插在p[i]的位置的前边!
如果i<j; && p[i]==p[j], 倒序插入中,第j个人先插入, 那么第i个人在保证插入的位置之前有
p[i]-1个空位的同时,又要插入到第 j 个人的后边!
1 #include<iostream>
2 #include<cstring>
3 #include<cstdio>
4 #include<algorithm>
5 #define M 200005
6 using namespace std;
7
8 pair<int, int>per[M];
9 int ret[M];
10 int tree[M*4];
11 int n;
12
13 void buildT(int p, int ld, int rd){
14 if(ld==rd){
15 tree[p]=1;
16 return ;
17 }
18 int mid=(ld+rd)>>1;
19 buildT(p<<1, ld, mid);
20 buildT(p<<1|1, mid+1, rd);
21 tree[p]=tree[p<<1]+tree[p<<1|1];
22 }
23
24 void updateT(int p, int ld, int rd, int pos, int val){
25 if(ld==rd){
26 tree[p]=0;
27 ret[ld]=val;
28 return ;
29 }
30 int mid=(ld+rd)>>1;
31 if(tree[p<<1]>pos)
32 updateT(p<<1, ld, mid, pos, val);
33 else
34 updateT(p<<1|1, mid+1, rd, pos-tree[p<<1], val);
35
36 tree[p]=tree[p<<1]+tree[p<<1|1];
37 }
38
39 int main(){
40 int i;
41 while(scanf("%d", &n)!=EOF){
42 buildT(1, 1, n);
43 for(i=1; i<=n; ++i)
44 scanf("%d%d", &per[i].first, &per[i].second);
45 for(i=n; i>=1; --i)
46 updateT(1, 1, n, per[i].first, per[i].second);
47
48 printf("%d", ret[1]);
49 for(i=2; i<=n; ++i)
50 printf(" %d", ret[i]);
51 printf("
");
52 }
53 return 0;
54 }
1 //树状数组~~不解释
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<algorithm>
6
7 #define N 200005
8 using namespace std;
9
10 int tree[N];
11 int pos[N], val[N];
12 int ret[N];
13 int n;
14
15 int lowbit(int x){
16 return x&(-x);
17 }
18
19 void buildT(){
20 for(int i=1; i<=n; ++i){
21 tree[i]=0;
22 for(int j=i-lowbit(i)+1; j<=i; ++j)
23 tree[i]+=1;
24 }
25 }
26
27 void updateT(int x){
28 while(x<=n){
29 tree[x]-=1;
30 x+=lowbit(x);
31 }
32 }
33
34 int getSum(int x){
35 int s=0;
36 while(x>0){
37 s+=tree[x];
38 x-=lowbit(x);
39 }
40 return s;
41 }
42
43 int main(){
44 while(scanf("%d", &n)!=EOF){
45 buildT();
46 for(int i=1; i<=n; ++i){
47 scanf("%d%d", &pos[i], &val[i]);
48 ret[i]=-1;
49 }
50 for(int i=n; i>=1; --i){
51 int ld=1, rd=n;
52 bool flag=false;
53 while(ld<=rd){
54 int mid=(ld+rd)>>1;
55 int s=getSum(mid);
56 //如果当前的位置没有人插入并且该位置的之前的人数恰好为pos[i]
57 if(ret[mid]==-1 && s==pos[i]+1){
58 updateT(mid);
59 ret[mid]=val[i];
60 flag=true;//已经找到不用在继续寻找了
61 break;
62 }
63 else if(s>=pos[i]+1)
64 rd=mid-1;
65 else ld=mid+1;
66 }
67 if(!flag) ret[rd+1]=val[i];//直到找到当前的位置没有人插入并且该位置的之前的人数恰好为pos[i]
68 }
69 printf("%d", ret[1]);
70 for(int i=2; i<=n; ++i)
71 printf(" %d", ret[i]);
72 printf("
");
73 }
74 return 0;
75 }