【poj2182】【poj2828】树状数组/线段树经典模型:逆序查找-空位插入法

poj2182题意:有一个1~n的排列,现在给定每个人前面有多少个人的编号比他大,求这个排列是什么。n<=8000

poj2182题解:

逆序做,可以确定二分最后一个是什么,然后删除这个数。树状数组维护每个数前面有多少个数比它小。

 

poj2828题意:有 n 个人排队买票,他们依次到来,第 i 个人来的时候会站在第pos[i]个人后面,并且他的编号为v[i]。
求最后的队列中每个位置人的编号。

poj2828题解:

来一个例子模拟:

0 (3) //编号为3的人插入第0个人后面

1 (2)

1 (1)

0 (4)

假设已经知道了最后的答案:

(4)(3)(1)(2)

类比上一题,我们可以逆序做,然后对于当前的最后一个人,它前面一定有且只有pos[i]个空位,就转化为上一题了。一但确定了一个人,那个空位就被填了,在树状数组上更新一下。

 

 1 //poj2182
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<iostream>
 7 #include<algorithm>
 8 using namespace std;
 9 
10 const int N=100010;
11 int n,a[N],c[N],ans[N];
12 
13 void add(int x,int d)
14 {
15     for(int i=x;i<=n;i+=(i&(-i))) c[i]+=d;
16 }
17 int getsum(int x)
18 {
19     int ans=0;
20     for(int i=x;i>=1;i-=(i&(-i))) ans+=c[i];
21     return ans;
22 }
23 
24 int main()
25 {
26     freopen("a.in","r",stdin);
27     scanf("%d",&n);
28     memset(c,0,sizeof(c));
29     for(int i=1;i<=n;i++) add(i,1);
30     a[0]=0;
31     for(int i=2;i<=n;i++)
32     {
33         scanf("%d",&a[i]);
34     }
35     int l,r,mid;
36     for(int i=n;i>=1;i--)
37     {
38         l=1,r=n;
39         while(l<r)
40         {
41             mid=(l+r+1)/2;
42             if(getsum(mid-1)>a[i]) r=mid-1; 
43             else l=mid;
44         }
45         ans[i]=l;
46         add(l,-1);
47     }
48     for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
49     return 0;
50 }
poj2182
 1 //poj2828
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<iostream>
 7 #include<algorithm>
 8 using namespace std;
 9 
10 const int N=200100;
11 int n,a[N],val[N],c[N],ans[N];
12 
13 void add(int x,int d)
14 {
15     for(int i=x;i<=n;i+=(i&(-i))) c[i]+=d;
16 }
17 int getsum(int x)
18 {
19     int ans=0;
20     for(int i=x;i>=1;i-=(i&(-i))) ans+=c[i];
21     return ans;
22 }
23 
24 int main()
25 {
26     freopen("a.in","r",stdin);
27     while(scanf("%d",&n)!=EOF)
28     {
29         memset(c,0,sizeof(c));
30         for(int i=1;i<=n;i++) add(i,1);
31         for(int i=1;i<=n;i++) scanf("%d%d",&a[i],&val[i]);
32         int l,r,mid;
33         for(int i=n;i>=1;i--)
34         {
35             l=1,r=n;
36             while(l<r)
37             {
38                 mid=(l+r+1)/2;
39                 if(getsum(mid-1)>a[i]) r=mid-1; 
40                 else l=mid;
41             }
42             ans[l]=i;
43             add(l,-1);
44         }
45         for(int i=1;i<=n;i++) printf("%d ",val[ans[i]]);printf("\n");
46     }
47     
48     return 0;
49 }
poj2828

 

posted @ 2016-11-03 11:32  拦路雨偏似雪花  阅读(302)  评论(0编辑  收藏  举报