POJ 2182 普通权值线段树求第k小

模板写错了,研究了一个多小时,哭死

int kth(int root,int start,int end,int k) {//查询第k小值是多少
	if(start==end)
		return start;
	int mid=(start+end)>>1,s1=tree[lson],s2=tree[rson];
	if(k<=s1)
		return kth(lson,start,mid,k);//向左子树搜索
	else
		return kth(rson,mid+1,end,k-s1);//向右子树搜索
}

倒数第二行k-s1不知道当初咋想的写成了k-mid,找了半天没发现错误,直到输出k发现有负数我才发现这个坑

回到题目

这题的英文是真恶心,读了几遍没读懂啥意思

题意:N头奶牛排队,它们的编号为1~n,知道每头牛前面有多少头比自己小,求每头牛的编号。

Sample Input

5
1
2
1
0

Sample Output

2
4
5
3
1

输入的第一行是N,第二行是乱序队列中第二头牛前面比他小的数目(不是0就是1,前面就一头),第一头省略了,肯定是0嘛,输出就是输出正序队列应有的编号

比如说样例输出后牛是这么排队的

1 3 5 4 2  右边为队首,左边为队尾 对着输入研究一下就能读懂题了

读懂题之后,我们发现,看最后一头牛的话,0就意味着前面有0头牛比他小,那他不就是第一小的么,就像你考试前面有0个人成绩比你高,那你就是第一了。那么,看最后一头牛,设输入为t[i],他就是第t[i]+1小。然后我们把牛出队就行了,循环看下一个队尾牛,直到队空,算法结束。

N<=8e4,嘿,不用动态开点了,很简单的题(如果模板没写错题目能读懂的话,这题我一开始愣是没读懂)

#include<cstdio>//权值线段树https://www.cnblogs.com/fusiwei/p/11301700.html
#include<iostream>
#define lson root<<1
#define rson root<<1|1
using namespace std;
const int N=1e6+10;
int a[N];//!!!初始数组,表示一开始元素的个数,建树要用! 
int tree[N<<1];
void build(int root,int start,int end) {//通常在主函数中这么使用:build(1,1,N);
	int mid=(start+end)>>1;
	if(start==end) {
		tree[root]=a[start];//a[start]表示数start有多少个
		return;
	}
	build(lson,start,mid);
	build(rson,mid+1,end);
	tree[root]=tree[lson]+tree[rson];
}
void update(int root,int start,int end,int k,int cnt) { //表示数k的个数多cnt个
	int mid=(start+end)>>1;
	if(start==end) {
		tree[root]+=cnt;
		return;
	}
	if(k<=mid)
		update(lson,start,mid,k,cnt);
	else
		update(rson,mid+1,end,k,cnt);
	tree[root]=tree[lson]+tree[rson];
}
int kth(int root,int start,int end,int k) {//查询第k小值是多少
	if(start==end)
		return start;
	int mid=(start+end)>>1,s1=tree[lson],s2=tree[rson];
	if(k<=s1)
		return kth(lson,start,mid,k);//向左子树搜索
	else
		return kth(rson,mid+1,end,k-s1);//向右子树搜索
}
int main() {
	int n;
	scanf("%d",&n);
	for(int i=1; i<=n; i++) { //1~n计数+1
		a[i]=1;
	}
	build(1,1,n);
	int t[8010]= {},ans[8010]= {};
	for(int i=2; i<=n; i++) { //t[i]前面有几头牛比他小,那么这头牛就是第t[i]+1小 
		scanf("%d",t+i);
	}
	for(int i=n; i>=1; i--) { //队列中最后一头牛i是第t[i]+1小,找到这头牛,然后出队,循环 ;
		ans[i]=kth(1,1,n,t[i]+1);
		update(1,1,n,ans[i],-1);
	}
	for(int i=1; i<=n; i++) {
		printf("%d\n",ans[i]);
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值