题目大意:人们一个一个的来排队并插队,按人到来的顺序给出每个人插队的位置(插在第几个人后面),并告知每个人的id号,输出最终队伍的情况。
思路:这道题假如你正向去处理的话,会发现,当你确定一个位置的时候,会面临之后还需要将这个位置以及这个位置后面的所有位置下调一个位置,这样在插入上,会有很大的复杂度。
所以遇到这种情况不如从后面开始向前遍历。而且这个时候他所要插入的位置便是他最终的位置,假如这个位置没有人的话,便不用动了。
而且将位置看作前面所需要留空的位置,便好处理很多(十分微妙,需要好好体会!)
sum[rt]表示区间空的位置
AC代码:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 200002
int sum[MAX << 2];
int ans[MAX];
int id[MAX];
int s[MAX];
void init(int l,int r,int rt)
{
if (l == r)
sum[rt] = 1;
else
{
int mid = (l + r) >> 1;
init(l, mid, rt << 1);
init(mid + 1, r, rt << 1 | 1);
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
}
int update(int pos, int l, int r, int rt)
{
sum[rt]--;
if (l == r)
return l;
int mid = (r + l) >> 1;
if (pos <= sum[rt << 1])
return update(pos, l, mid, rt << 1);
else
return update(pos - sum[rt << 1], mid + 1, r, rt << 1 | 1);
}
int main()
{
int n;
while (cin >> n)
{
init(1, n+1, 1);
for (int i = 0; i < n; i++)
scanf("%d%d", &id[i], &s[i]);
for (int i = n - 1; i >= 0; i--)
{
ans[update(id[i]+1, 1, n+1, 1)-1] = s[i];
}
printf("%d", ans[0]);
for (int i = 1; i <n; i++)
printf(" %d", ans[i]);
cout << endl;
}
}
POJ 2182
给出的数字表示从第2到第n只牛左边有几个比它序号小的牛,要求每个位置的牛的编号是多少
思路与上面的一样,只有最后一个你才能够真正的确认编号
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 8008
#define ls rt<<1
#define rs rt<<1|1
#define m (l+r)>>1
int sum[MAX << 2];
int a[MAX];
int ans[MAX];
bool vis[MAX];
void uprt(int rt)
{
sum[rt] = sum[ls] + sum[rs];
}
void build(int l, int r, int rt)
{
if (l == r)
{
sum[rt] = 1;
return;
}
int mid = m;
build(l, mid, ls);
build(mid + 1, r, rs);
uprt(rt);
}
int query(int p, int l, int r, int rt)
{
sum[rt]--;
if (l == r)
return l;
int mid = m;
int ans = 0;
if (p < sum[ls])
ans = query(p, l, mid, ls);
else
ans = query(p - sum[ls], mid + 1, r, rs);
}
int main()
{
int n;
while (cin >> n)
{
build(1, n, 1);
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n-1; i++)
scanf("%d", &a[i]);
for (int i = n - 2; i >= 0;i--)
{
ans[i] = query(a[i], 1, n, 1);
vis[ans[i]] = 1;
}
for (int i = 1; i <= n;i++)
if (!vis[i])
cout << i << endl;
for (int i = 0; i < n - 1; i++)
cout << ans[i] << endl;
}
}