【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 }
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 }