链接:http://poj.org/problem?id=2828
题意:
一个排队的队列
T组操作
每次输入a b表示在第a个人后面插队,插队的人是b
最后输出整个队伍的顺序
思路:
采用从后往前推的思路,往队列中填人
在代码里解释的很清楚了,很好的题目!!
#include<cstdio> #include<algorithm> #include<iostream> #include<string> #include<cstring> #include<cstdlib> #include<cmath> #include<set> #include<map> #include<vector> #include<queue> #include<ctime> using namespace std; #define lson l,m,rt*2 #define rson m+1,r,rt*2+1 #define calm (l+r)/2 #define maxn 200010 struct node{ int pos, val; }; int sum[maxn * 4]; int ans[maxn]; node op[maxn]; void build(int l, int r, int rt)//建树的时候就保存当前区间里剩余多少空位 { sum[rt] = r - l + 1; if (l == r) return; int m = calm; build(lson); build(rson); } /* 填入的时候,知道是第几个人,实际就是从前往后数的第几个人 那么找人的时候,要么填入左子树,要么填入右子树 填入左子树的时候编号不变 但是填入右子树的时候,编号就发生改变了,要减去原先左子树里面的人 才是他在右子树里的编号 */ void update(int pos, int val, int l, int r, int rt) { if (l == r)//填到叶子节点的时候,当前的l和r就是他在整个队列中的位置,所以可以直接填入ans数组 { sum[rt] = 0;//把当前位子的位子-1 ans[l] = val; return; } int m = calm; if (pos <= sum[rt * 2])//填入的人是第pos个人,如果左子树里没有pos个空位,那么就无法填入左树 update(pos, val, lson); else update(pos - sum[rt * 2], val, rson); sum[rt]--;//填入以后每一层人数-1 } int main() { // freopen("D://input.txt", "r", stdin); // freopen("D://output.txt", "w", stdout); int n; while (scanf("%d", &n) != EOF) { build(1, n, 1);//以第1个人到第n个人建树 int i; for (i = 0; i < n; i++) { scanf("%d%d", &op[i].pos, &op[i].val); } /* 倒着来的原因是: 最后输入的那个编号,如果是0,那么他一定是整个队列中的第一个人 所以倒着推可以避免插队操作,直接按最后的顺序一个个填就行了 不理解的可以手动模拟一遍 */ for (i = n - 1; i >= 0; i--) { update(op[i].pos + 1, op[i].val, 1, n, 1);//输入0的时候实际是第一个人,所以输入编号+1 } for (i = 1; i <= n; i++) { if (i != 1) printf(" "); printf("%d", ans[i]); } printf("\n"); } // printf("\n%.3lf\n",clock()/CLOCKS_PER_SEC); return 0; }