您的位置:首页 > 其它

2016夏季练习——线段树

2016-07-18 16:00 267 查看
来源:POJ2182

解释在注释里面

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 8000+10;
struct Tree{
int l,r;
int len;
Tree():len(0){}
};
int n;
int a[MAXN];
int ans[MAXN];
Tree tree[MAXN*4];
void build(int rt,int left,int right){
tree[rt].l=left;
tree[rt].r=right;
tree[rt].len=right-left+1;
if(left==right) return ;
int mid=(left+right)>>1;
build(rt<<1,left,mid);
build(rt<<1|1,mid+1,right);
}
int query(int rt,int tot){
tree[rt].len--;
//关键就是这一步!!!
//我们访问这个节点,也就意味着这个节点所表示的区间中有我需要的那个值
//那么我取走那个值的时候,对应后面的数就不能把这个节点数算在里面
//cout<<rt<<" "<<tree[rt].l<<" "<<tree[rt].r<<" "<<tree[rt].len<<" "<<tot<<endl;
if(tree[rt].l==tree[rt].r) {
//cout<<"leaves!!!"<<endl;
return tree[rt].l;
}
//下面是访问策略
//根据上面的分析可以知道
//结构中len的使用其实不能叫做len
//表示的是当前区间中小于r但是还没有被使用过的数字
//这样的话下面的这个就是显然的了
if(tot>tree[rt<<1].len) {
//cout<<"right"<<endl;
return query(rt<<1|1,tot-tree[rt<<1].len);
}
else {
//cout<<"left"<<endl;
return query(rt<<1,tot);
}
}
int main(){
scanf("%d",&n);
build(1,1,n);
memset(a,0,sizeof(a));
/*for(int i=1;i<=2*n-1;i++)
cout<<i<<" "<<tree[i].l<<" "<<tree[i].r<<" "<<tree[i].len<<endl;*/
for(int i=2;i<=n;i++){
scanf("%d",a+i);
}

//注意,我们最后一个数其实有着自己的性质:因为前面的所有数都已经出来了
//所以我们最后一个一定是a[i]+1
//这样,我们继续向前的时候,我们将遇到一个问题:
//我已经用过的这个数应该是怎么办?
//我们去query函数中看这个问题。
for(int i=n;i>0;i--){
//cout<<"n="<<i<<": a[i]="<<a[i]<<endl;
ans[i]=query(1,a[i]+1);
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: