树状数组+二分or暴力出奇迹---lost cows

描述:

N(2<=N<=8,000)奶牛有独特的品牌在范围1.N.在一个糟糕的判断力的壮观显示,他们去附近的‘水坑’,并喝了太多啤酒在晚餐前。当是时候排队为他们的晚餐,他们没有排队按照所需的上升数字的顺序,他们的品牌。
令人遗憾的是,FJ没有办法解决这些问题。此外,他不太擅长观察问题。他没有写下每头牛的品牌,而是确定了一个相当愚蠢的统计数据:每一头排在奶牛前面的奶牛,他知道排在那头牛前面的奶牛的数量,事实上,这些奶牛的品牌比那头牛要小。
根据这些数据,告诉FJ奶牛的确切顺序。

输入

*第1行:单个整数,N

*第2行.N:这些N1线描述的是排在一头母牛前面的奶牛的数量,并有比那头牛更小的品牌。当然,没有奶牛排在第一头牛的前面,所以她没有被列在名单上。输入的第2行描述在槽#2中品牌小于牛的前面奶牛的数量;第3行描述品牌小于槽#3中的牛的前面奶牛的数量,以此类推。

输出量

*第1行.N:每一行输出的N条都告诉奶牛的品牌。输出的第1行告诉第一头奶牛的品牌,第2行告诉第二头奶牛的品牌,依此类推。

样本输入

5
1
2
1
0

样本输出

2
4
5
3
1

 1:不知为何,其他人说的树状数组是用找0的个数,根据我自几的理解,就是从后面的位置一次向前遍历,找到对应位置的牛的编号,在树状数组里,某一编号下的数值是1,说明该编号的牛还没有被安放下,否则为0;

 2:根据牛前面有k个小于它的牛,用二分查询,具体看代码

树状数组+二分:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
ll c[10000],temp[10000],pa[10000];
ll n;
ll lowbit(ll x){
	return x&(-x);
}

ll update(ll pos,ll cnt){
	while(pos<=n){
		c[pos]+=cnt;
		pos+=lowbit(pos);	
	}
}

ll getsum(ll pos){
	ll sum=0;
	while(pos>0){
		sum+=c[pos];
		pos-=lowbit(pos);
	}
	return sum;
}
//二分查找牛的编号 
ll find(ll cnt){//找第cnt个有效的1 
	ll l=1,r=n;
	while(l<=r){
		ll mid=(l+r)>>1;
		ll num=getsum(mid);//前面有num头比编号该牛小的 
		if(num<cnt){//
			l=mid+1;//说明l需要扩大 
		}
		else if(num>=cnt)//说明r需要缩小 
				r=mid-1;
	}
	return l;
}

int main(){
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++){
		update(i,1);//初始化树状数组 
	}
	for(ll i=2;i<=n;i++){
		scanf("%lld",pa+i);
	}
	for(ll i=n;i>=1;i--){
		ll pos=find(pa[i]+1);//找第pa[i]+1个有效1 
		update(pos,-1);//该位置牛被安放,置0 
		temp[i]=pos;
	}
	for(ll i=1;i<=n;i++){
		printf("%lld\n",temp[i]);
	}
	return 0;
}

 暴力:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
vector<ll> p;
ll stack[9000];
int main(){
	ll n;
	cin>>n;
	for(ll i=1;i<=n;i++){
		p.push_back(i);//1~n顺序存储 
	}
	ll cnt;
	for(cnt=1;cnt<n;cnt++){
		cin>>stack[cnt];
	}
	ll a[9000];
	ll mm=0;
	for(cnt--;cnt>=1;cnt--){//寻找牛从后往前找 
		a[++mm]=p[stack[cnt]];//如果在剩下的牛中有k个比其小的,该牛其实就是p[k]; 
		p.erase(p.begin()+stack[cnt]);//找到该位置的牛,将其移除 
	}
	a[++mm]=p[0];//第一个位置的牛 
	p.pop_back();
	for(;mm>0;mm--){
		cout<<a[mm]<<endl;
	}
	return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值