POJ 2828(Buy Tickets)

题意:有n个人在排队,他们都要想插队,每个人有自己想要排的位置(想排第几个人的后面)和自己的编号,求最终每个人的位置。
思路:这题思路是最重要的,至于怎样实现有很多种方法;这题可以变为从最后一个人开始往前算,因为这样算出来就是最终位置了,然后问题就可以转为每个人排第几个空位了。。这样就可以用线段树或树状数组实现了,我用了三种方法实现,第一种是自己想的,也是最挫的,第二第三种是参考别人思路的


1.树状数组 + 二分 

复杂度O(nlog^2n)

#include <cstdio>

const int N = 300010;
int n, pos[N], idx[N];
struct BIT{
	int sum, idx;	
}arr[N];

inline int lowbit(int x){
	return x & (-x);
}

void update(int loc, int val, int idxx){
	arr[loc].idx = idxx;
	while(loc <= n){
		arr[loc].sum += val;
		loc += lowbit(loc);
	}
}

int query(int loc){
	int res = 0;
	while(loc){
		res += arr[loc].sum;
		loc -= lowbit(loc);
	}
	return res;
}

int BSearch(int l, int r, int val){
	int mid;
	while(l < r){
		mid = (l + r) >> 1;
		int sum = query(mid);
		if(sum < val)
			l = mid + 1;
		else
			r = mid;
	}
	return l;
}

int main(){
	while(~scanf("%d", &n)){
		int i;
		for(i = 1;i <= n;i++)
			arr[i].sum = 0;
		for(i = 1;i <= n;i++)
			update(i, 1, 0);
		for(i = 1;i <= n;i++)
			scanf("%d%d", &pos[i], &idx[i]);
		for(i = n;i >= 1;i--){
			int loc = BSearch(1, n, pos[i] + 1);
			update(loc, -1, idx[i]);
		}
		for(i = 1;i <= n;i++)
			printf("%d%c", arr[i].idx, i != n?' ':'\n');
	}	
	return 0;
}

2.线段树

复杂度O(nlogn)

#include <cstdio>

const int N = 200010;
int n, pos[N], val[N], ans[N];
struct segTree{
	int lc, rc, sum, idx;
}arr[N * 4];

void pushUp(int idx){
	arr[idx].sum = arr[idx * 2].sum + arr[idx * 2 + 1].sum;	
}

void build(int idx, int l, int r){
	arr[idx].lc = l, arr[idx].rc = r;
	if(l == r){
		arr[idx].sum = 1;
		arr[idx].idx = l;
		return ;
	}
	int mid = (l + r) >> 1;
	build(idx * 2, l, mid);
	build(idx * 2 + 1, mid + 1, r);
	pushUp(idx);	
}

void insert(int idx, int loc, int values){
	arr[idx].sum--;
	if(arr[idx].lc == arr[idx].rc){
  		ans[arr[idx].lc] = values;
		return ;
	}
	if(arr[idx * 2].sum >= loc)
		insert(idx * 2, loc, values);
	else{
		loc -= arr[idx * 2].sum;
		insert(idx * 2 + 1, loc, values);
	}
}

int main(){
	while(~scanf("%d", &n)){
		int i;
		build(1, 1, n);
		for(i = 1;i <= n;i++)
			scanf("%d%d", &pos[i], &val[i]);		
		for(i = n;i >= 1;i--)
			insert(1, pos[i] + 1, val[i]);
		for(i = 1;i <= n;i++)
			printf("%d%c", ans[i], i != n?' ':'\n');
	}	
	return 0;
}

3.树状数组的高端应用。。

时间复杂度:O(nlogn)  空间复杂度:O(n)

#include <cstdio>

const int N = 200010;
int pos[N], val[N], n, ans[N], bits[N];

inline int lowbit(int x){
	return x & (-x);
}

void initiBIT(){
	for(int i = 1;i <= n;i++)
		bits[i] = lowbit(i);
}

void update(int loc){
	while(loc <= n){
		bits[loc]--;
		loc += lowbit(loc);
	}
}

int query(int loc){
	int ans = 0, sum = 0, i;
    for (i = 18; i >= 0; i--){
        ans += (1 << i);
        if (ans >= n || sum + bits[ans] >= loc) 
			ans -= (1 << i);
        else 
			sum += bits[ans];
    }
    return ans + 1;
}

int main(){
	while(~scanf("%d", &n)){
		int i;
		initiBIT();
		for(i = 1;i <= n;i++)
			scanf("%d%d", &pos[i], &val[i]);
		for(i = n;i >= 1;i--){
			int loc = query(pos[i] + 1);
			ans[loc] = val[i];
			update(loc);
		}
		for(i = 1;i <= n;i++)
			printf("%d%c", ans[i], i != n?' ':'\n');
	}	
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值