您的位置:首页 > 编程语言

POJ 2828 Buy Tickets 题解&代码

2015-12-03 19:43 369 查看
题目大意:对于每组数据,给出一个空队列,有m次插入,每次插入都将在队列的第pos[i]处插入一个值val[i],输出队列最后的状态。

思路:

在第pos[i]处插入一个元素,则第pos[i]处后的所有元素都将向后移动一位,看起来是平均每次插入需要n次操作。

但是我们可以看出,对每次插入来说,本次插入结束后本次所插入的元素位置一定会是pos[i]+1,那么与其先插入可能会需要向后移动的元素,不如从最后一个被插入的元素开始向一个[0,m]的空区间插入元素,这样每一次插入都不会对已经记录的状态产生影响。

这样的话,可以将这道题转换成线段树来做,用一个s标记统计区间内被插入的元素数,用v数组记录区间上的单点被插入值。

第i个元素的位置应当是从0开始的空位置中的第pos[i]个,我们可以用(r-l+1)-s[o]来统计区间编号为o的区间内有多少个空位置,如果(r-l+1)-s[o]>pos[i],那么这个区间包含该元素应该被插入的区间。

对代码能力要求不高,注意判定的细节和线段树的特性,基本上过样例就说明AC…我这种手残大约40min就调过了

**代码中的边界判定与思路中所说有微小区别

#include<iostream>
#include<stdio.h>
#define lson (o<<1)
#define rson ((o<<1)|1)
using namespace std;
const int maxn=200005;
bool flag,f;
int n,p[maxn],val[maxn],v[maxn],s[maxn*4];
void build_tree(int o,int l,int r)
{
s[o]=0;
if(l==r)
{
v[l]=0;
return;
}
int mid=(l+r)/2;
build_tree(lson,l,mid);
build_tree(rson,mid+1,r);
}
void maintain(int o,int l,int r)
{
s[o]=s[lson]+s[rson];
}
void add_tree(int o,int l,int r,int z,int x)
{
if(l==r)
{
if(s[o])return;
v[l]=x;
s[o]=1;
f=true;
return;
}
int mid=(l+r)/2;
if(mid>=z && z<=(mid-l+1)-s[lson])add_tree(lson,l,mid,z,x);
else
{
z-=(mid-l+1)-s[lson];
add_tree(rson,mid+1,r,z,x);
}
maintain(o,l,r);
}
void print_tree(int o,int l,int r)
{
if(l==r)
{
if(flag)printf(" %d",v[l]-1);
else printf("%d",v[l]-1);
flag=true;
return;
}
int mid=(l+r)/2;
print_tree(lson,l,mid);
print_tree(rson,mid+1,r);
}
int main(void)
{
while(cin>>n)
{
flag=false;
build_tree(1,1,n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&p[i],&val[i]);
p[i]++;val[i]++;
}
for(int i=n;i>0;i--)
{
f=false;
add_tree(1,1,n,p[i],val[i]);
}
print_tree(1,1,n);
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: