POJ 2828 Buy Tickets 线段树
题意:给出一些人和每个人的入队时在队列的位置。每个人都有一个值val,输出俺顺序输出队列的val,数据量 200000
如果用链表肯定超时,于是乎,用二叉树,but TLE了,才醒悟过来,如果二叉树是个左斜树或右斜树不就跟链表复杂度一样的么。。。
百度是个好东西,原来是线段树,不管什么数据量,可以达到logN,不过题目一般都会让人动脑子,要会转化等等,该题有个小特点,最后插入的数的位置,一定是最终位置,
所以要从后往前放入线段树。最后自己写了一组数据死活过不了,一提交AC,系统有问题?还真不是,那是一组不靠谱的错误数据。。。囧,写数据也要合理才行
每个线段有一个num值,记录该区间可以放几个数
根据数的序号把数加入线段树,之后,这个位置所在的区间可以放得数就减少一个,上推。。。整个区间可以放得数个数也减少一个
代码:
/* 线段树 */ #include<iostream> #include<cstdio> #include<cstring> #include<string> #define nMAX 200015 using namespace std; struct Tree { int l,r,num; }tree[nMAX*4]; struct Node { int val,id; }node[nMAX]; int n,mark,ans[nMAX]; void create(int l,int r,int u) { tree[u].num=r-l+1; tree[u].l=l, tree[u].r=r; if(l==r) return ; int mid=(l+r)/2; create(l,mid,2*u); create(mid+1,r,2*u+1); } void update(int u) { tree[u].num--; if(tree[u].l==tree[u].r) {ans[tree[u].l]=node[mark].val;return;} if(node[mark].id<=tree[2*u].num) update(2*u); else { node[mark].id-=tree[2*u].num; update(2*u+1); } } int main() { int i,j; while(~scanf("%d",&n)) { for(i=1;i<=n;i++) { scanf("%d%d",&node[i].id,&node[i].val); node[i].id++; } create(1,n,1); for(i=n;i>=1;i--) { mark=i; update(1); } for(i=1;i<=n;i++) { if(i==1)printf("%d",ans[i]); else printf(" %d",ans[i]); } printf("\n"); } return 0; }