1、poj2828 Buy Tickets
http://poj.org/problem?id=2828
百度一下,基本上是线段树的解法,但是做过先前树状数组系列题目,我们会发现这道题和SPOJ 227 Ordering the Soldiers http://www.spoj.pl/problems/ORDERS / (见博客树状数组6)很相似,解法基本一样。从后往前确定人的位置,每确定一个人的位置,我们就把这个人忽略,这样剩下的人的相对位置保持不变,继续确定最后一个人的位置,重复以上过程。明白了这解法基本套用SPOJ 227。奉上树状数组版本(map超时。。。。)
树状数组:
#include <stdio.h>
#include <string.h>
using namespace std;
const int MAX = 200000+10;
int n, c[MAX], a[MAX], b[MAX];
int mapii[MAX];
int lowbit(int x)
{
return x&(-x);
}
void update(int x, int v)
{
while (x<=n)
{
c[x] += v;
x += lowbit(x);
}
}
int getsum(int x)
{
int sum = 0;
while (x)
{
sum += c[x];
x -= lowbit(x);
}
return sum;
}
int find(int x)
{
int l = 1, r = n, mid;
while (l < r)
{
mid = (l + r) >> 1;
if (getsum(mid) < x)
{
l = mid+1;
}
else
{
r = mid;
}
}
return r;
}
int main()
{
int i, t;
while (scanf("%d", &n) == 1)
{
memset(c, 0, sizeof(c));
//mapii.clear();
for (i=1; i<=n; i++)
{
update(i, 1);
scanf("%d%d", a+i, b+i);
}
for (i=n; i>=1; i--)
{
t = find(a[i]+1);
//printf("%d\n", getsum(a[i]+1));
mapii[t] = b[i];
update(t, -1);
}
printf("%d", mapii[1]);
for (i=2; i<=n; i++)
{
printf(" %d", mapii[i]);
}
puts("");
}
}
/*
4
0 77
1 51
1 33
2 69
*/
线段树版本:
#include <stdio.h>
const int MAX = 200000 + 10;
int n, map[MAX], c[MAX], b[MAX];
struct node
{
int l;
int r;
int v;
}a[MAX<<2];
void pushup(int pos)
{
a[pos].v = a[pos<<1].v + a[pos<<1|1].v;
}
void build(int l, int r, int pos)
{
a[pos].l = l;
a[pos].r = r;
if (l == r)
{
a[pos].v = 1;
return;
}
int mid = (l + r) >> 1;
build(l, mid, pos<<1);
build(mid+1, r, pos<<1|1);
pushup(pos);
}
int query(int goal, int pos)
{
int ans;
if (a[pos].l == a[pos].r)
{
a[pos].v-=1;
return a[pos].l;
}
if (a[pos<<1].v>=goal)
{
ans = query(goal, pos<<1);
}
else
{
ans = query(goal-a[pos<<1].v, pos<<1|1);
}
pushup(pos);
return ans;
}
int main()
{
int i;
while (scanf("%d", &n) == 1)
{
build(1, n, 1);
for (i=1; i<=n; i++)
{
scanf("%d%d", c+i, b+i);
}
for (i=n; i>=1; i--)
{
map[query(c[i]+1, 1)] = b[i];
}
printf("%d", map[1]);
for (i=2; i<=n; i++)
{
printf(" %d", map[i]);
}
puts("");
}
}