题意:人们一个一个的来排队并插队,按人到来的顺序给出每个人插队的位置(插在第几个人后面),并告知每个人的id号,输出最终队伍的情况。
思路:按照hint给的思路显然是n2复杂度,对于200000个点来说大了点。
1、按照与2182同样的思路可以用树状数组来做。只不过这次二分是求第i个人应该最终排在哪个位置。(树状数组版本2中,tree[i]存放的是1~i的空余位置,具体思路见代码注释)
2、线段树也能做,记录区间目前还剩的空位数量,每一次插入的时候,如果该节点左儿子的空余数量>x,那么只要在左儿子找就可以了;否则要在右儿子中找,此时x改为x-左儿子num。
树状数组代码:
#include <stdio.h>
#include <string.h>
#define N 200005
int n;
int a[N],res[N],s[N],tree[N];
int lowbit(x){
return x&(-x);
}
void add(int x){
int i;
for(i = x;i<=n;i+=lowbit(i))
tree[i]++;
}
int sum(int x){
int i,ans=0;
for(i = x;i>=1;i-=lowbit(i))
ans += tree[i];
return ans;
}
int bisearch(int x){
int low,high,mid;
low = 1,high = n;
while(low < high){
mid = (low+high)>>1;
if(x + sum(mid) >= mid)
low = mid+1;
else
high = mid;
}
return low;
}
int main(){
freopen("a.txt","r",stdin);
while(scanf("%d",&n)!=EOF){
int i,j;
memset(tree,0,sizeof(tree));
for(i = 1;i<=n;i++)
scanf("%d %d",&a[i],&s[i]);
for(i = n;i>=1;i--){
j = bisearch(a[i]);
res[j] = s[i];
add(j);
}
for(i = 1;i<=n;i++)
printf("%d ",res[i]);
putchar('\n');
}
return 0;
}
树状数组代码,版本2:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <cstdlib>
using namespace std;
#define clc(s,t) memset(s,t,sizeof(s))
#define INF 0x3fffffff
#define N 200005
int tree[N],a[N],s[N],res[N];
int n;
int lowbit(int x){
return x&(-x);
}
void add(int i,int x){
for(int j = i;j<=n;j+=lowbit(j))
tree[j] += x;
}
int sum(int i){
int res = 0;
for(int j = i;j>=1;j-=lowbit(j))
res += tree[j];
return res;
}
int search(int d,int x){//相当于要插入的位置是d右侧的第x个空位上
int high,mid,low,tmp;
low = d;
high = n;
while(low < high){
mid = (low+high)>>1;
tmp = sum(mid) - sum(d);
if(tmp < x)//二分时要注意:tmp==x是不能直接输出mid,因为mid处可能已经填过东西,所有要找到最靠左的tmp==x处
low = mid+1;
else
high = mid;
}
return low;
}
int main(){
while(scanf("%d",&n) != EOF){
int i,j;
clc(tree,0);
for(i = 1;i<=n;i++){
scanf("%d %d",&a[i],&s[i]);
add(i,1);
}
for(i = n;i>=1;i--){
j = search(a[i]+1,a[i]+1-sum(a[i]+1));//a[i]+1-sum(a[i]+1)表示要插入的位置左侧已经插入了多少个人
add(j,-1);
res[j] = s[i];
}
for(i = 1;i<=n;i++)
printf("%d ",res[i]);
putchar('\n');
}
return 0;
}
线段树代码:
#include <stdio.h>
#include <string.h>
#define N 200005
struct node{
int left,right;
int num;
}p[N<<2];
int a[N],s[N],res[N],n;
void create(int id,int left,int right){
int mid;
p[id].left = left;
p[id].right = right;
if(left == right){
p[id].num = 1;
return;
}
mid = (left+right)>>1;
create(id<<1,left,mid);
create((id<<1)+1,mid+1,right);
p[id].num = p[id<<1].num + p[(id<<1)+1].num;
}
int query(int id,int x){
p[id].num--;
if(p[id].left == p[id].right)
return p[id].left;
if(p[id<<1].num <= x)
query((id<<1)+1,x-p[id<<1].num);
else
query(id<<1,x);
}
int main(){
freopen("a.txt","r",stdin);
while(scanf("%d",&n)!=EOF){
int i,j;
for(i = 1;i<=n;i++)
scanf("%d %d",&a[i],&s[i]);
create(1,1,n);
for(i = n;i>=1;i--){
j = query(1,a[i]);
res[j] = s[i];
}
for(i = 1;i<=n;i++)
printf("%d ",res[i]);
putchar('\n');
}
return 0;
}