(POJ) 2182 Lost Cows (贪心 or 树状数组)

本文详细解析了一种针对牛群排序的问题,通过贪心算法和树状数组实现从后向前的递推解决策略。首先介绍了如何直接确定最后一头牛的位置,接着通过二分查找和树状数组维护的比当前牛编号小的数字数量,逐步确定每头牛的准确位置。文章提供了两种实现方式的代码示例,一种是基于贪心思想的简单迭代,另一种则是利用树状数组进行优化。

传送门

题意:n头牛,每头牛有[1,n]的独立的编号,现在这些牛杂乱的站在一排,给出在第i头牛之前,并且比第i头牛编号小的个数,i属于2到n。求解现在的每头牛的编号

思路:我们从后往前考虑即可,其实最后一头牛的id都是可以直接确定的,贪心递推(不知道该不该称这个为贪心)即可,点然我们也许可以用树状数组,我是直接用的别人的了,也是从后往前考虑,然后二分当前牛的编号,通过前面比它小的牛和后面比它小的牛来判断即可,树状数组维护的就是当前牛后面比它小的数字。最终该牛的id 是要满足id-1=k(前边比他小的数字个数,已知)+num(后面比它小的数字,树状数组维护)。
 

//贪心
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
//#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b)	for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-9;
const int maxn=1e5+5;
int n,r[maxn],ans[maxn];
vector<int> tt;
int main() {
	while(sc(n)!=EOF) {
		tt.resize(n+5);
		tt[1]=1;
		rep(i,2,n)	sc(r[i]),tt[i]=i;
		drep(i,n,1) {
			ans[i]=tt[r[i]+1];
			tt.erase(tt.begin()+r[i]+1);
		}
		rep(i,1,n)	cout<<ans[i]<<endl;
		tt.clear();
	}
	return 0;
}
//树状数组
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<cmath>
#include<sstream>
//#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define fi first
#define se second
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define sc(n) scanf("%d",&n)
#define SC(n,m) scanf("%d %d",&n,&m)
#define SZ(a) int((a).size())
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define drep(i,a,b)	for(int i=a;i>=b;--i)
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define MAX 8005
int a[MAX],ans[MAX],tree[MAX],n;
il int ask(int pos){
	int ans=0;
	while(pos>0)	ans+=tree[pos],pos-=pos&(-pos);
	return ans;
}
il void add(int pos,int val){
	while(pos<=n)	tree[pos]+=val,pos+=pos&(-pos);
}
il int solve(int k){
	int left=1,right=n;
	while(left<right){
		int mid=(left+right)>>1;
		int num=ask(mid);
		if(mid-1<num+k) 	left=mid+1;
		else 	right=mid;
	}
	return left;
}
int main() {
	while(sc(n)!=EOF){
		ms(tree,0);
		a[1]=0;
		rep(i,2,n)	sc(a[i]);
		drep(i,n,1){
			int k=solve(a[i]);
			add(k,1);
			ans[i]=k;
		}
		rep(i,1,n)	cout<<ans[i]<<endl;
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值