POJ_2828_Buy Tickets
题意:插队问题;
2016.5.20,复习这道题。
总结:线段树基础不牢,建树,更新尚不熟悉,注意加强理解记忆。
主要理解:(单点更新,逆序插入)
发生插队时,前面的队伍是连续没有空位的,即pos:2,1,这种情况不会出现,至少应该为pos:1,2,1
插入顺序是逆序的(最后插入的val的位置不会再发生变化),如果正序插入则每个val的顺序是动态的。
插入pos,那么在pos这个位置之前应该还有pos-1个空位。
访问右节点的时候注意pos要修改,改为pos-sum[rt],即整个线段的第pos个空位,在下一个右儿子那的第pos-sum[rt]个空位。
void Insert(int pos,int val,int l,int r,int rt)
{
if(l==r)
{
spare[rt]=0;
seq[l]=val;
return;
}
int mid=(r+l)>>1;
if(pos<=spare[rt<<1])
Insert(pos,val,l,mid,rt<<1);
else
Insert(pos-spare[rt<<1],val,mid+1,r,rt<<1|1);
PushUp(rt);
}
代码:
#include<iostream>
#include<cstdio>
using namespace std;
#define N 200005
int spare[N<<2];
int seq[N];
void PushUp(int rt)
{
spare[rt]=spare[rt<<1]+spare[rt<<1|1];
}
void build(int l,int r,int rt)
{
if(l==r)
{
spare[rt]=1;
return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
PushUp(rt);
}
void Insert(int pos,int val,int l,int r,int rt)
{
if(l==r)
{
spare[rt]=0;
seq[l]=val;
return;
}
int mid=(r+l)>>1;
if(pos<=spare[rt<<1])
Insert(pos,val,l,mid,rt<<1);
else
Insert(pos-spare[rt<<1],val,mid+1,r,rt<<1|1);
PushUp(rt);
}
int main()
{
int n,p[N],v[N];
while(scanf("%d",&n)!=EOF)
{
build(1,n,1);
int i;
for(i=1;i<=n;i++)
{
scanf("%d%d",&p[i],&v[i]);
p[i]++;
}
for(i=n;i>0;i--)
{
Insert(p[i],v[i],1,n,1);
}
for(i=1;i<=n;i++)
{
if(i!=n)
printf("%d ",seq[i]);
else
printf("%d\n",seq[i]);
}
/*for(i=1;i<=n;i++) //如果这样输出就会超时,线段树容易超时
{
printf("%d",seq[i]);
if(i!=n)
printf(" ");
else
printf("\n");
}*/
} return 0; }
浙公网安备 33010602011771号