售票系统——线段树
描述:某次列车途经C个城市,城市编号依次为1到C,列车上共有S个座位,铁路局规定售出的车票只能是坐票,即车上所有的旅客都有座。售票系统是由计算机执行的,每一个售票申请包含三个参数,分别用O、D、N表示,O为起始站,D为目的地站,N为车票张数。售票系统对该售票申请作出受理或不受理的决定,只有在从O到D的区段内列车上都有N个或N个以上的空座位时该售票申请才被受理。请你写一个程序,实现这个自动售票系统。
题目就是要求实现两种操作,1、求一段区间的最大值/最小值;2、给一段区间上的每一个数加上一个值。
对于区间,理应想到线段树。而线段树是十分灵活的,几乎每道题目都不一样,其中关于要在结点中保存哪些信息的问题就值得思考。
要快速地查询区间最值,首先考虑用seg[i].max表示该区间内的最大值,这样一来,执行“给[a,b]区间每个数增加d”的时候,只需要递归到一个完整的被覆盖着的区间,将这个区间的max增加d即可,回溯时更新父结点。但是这么做是有问题的,某个被覆盖过的区间以上的区间信息确实没有问题,但是它以下呢?max值是不能够向下传递的!所以需要增加区间信息。
给出如下结果:
1、seg[i].max表示结点i表示的区间的最大值;
2、seg[i].cover表示结点i表示的区间被某个售票申请直接覆盖的数量
这样一来,需要统计某个已经被覆盖的区间的子结点的信息时,将cover所包含的信息向下传递即可。因为cover是可以向下传递的:一个区间的值全部增加d,它的子结点的值也必然全部增加d。
以下是我的代码:
#include
<
stdio.h
>
#define maxn 60007
#define L(x) (x<<1)
#define R(x) ((x<<1)+1)
#define max(a,b) (a>b?a:b)
struct
{
long a,b;
long max,cover;
}seg[maxn * 3 ];
long n,s,m;
void build( long node, long x, long y)
{
long mid = (x + y) >> 1 ;
seg[node].a = x;seg[node].b = y;
seg[node].max = seg[node].cover = 0 ;
if (x < y)
{
build(L(node),x,mid);
build(R(node),mid + 1 ,y);
}
}
bool ok( long node, long x, long y, long d)
{
long a = seg[node].a,b = seg[node].b,mid = (a + b) >> 1 ;
bool re = false ,cal = false ;
if (x <= a && b <= y)
return (seg[node].max + d <= s);
if (seg[node].cover > 0 )
{
seg[L(node)].cover += seg[node].cover;
seg[R(node)].cover += seg[node].cover;
seg[L(node)].max += seg[node].cover;
seg[R(node)].max += seg[node].cover;
seg[node].cover = 0 ;
seg[node].max = max(seg[L(node)].max,seg[R(node)].max);
}
if (mid >= x)
{
re = ok(L(node),x,y,d);
cal = true ;
}
if (mid + 1 <= y)
re = ((re ||! cal) && ok(R(node),x,y,d));
return re;
}
void insert( long node, long x, long y, long d)
{
long a = seg[node].a,b = seg[node].b,mid = (a + b) >> 1 ;
if (x <= a && b <= y)
{
seg[node].max += d;
seg[node].cover += d;
}
else
{
if (mid >= x)
{
insert(L(node),x,y,d);
seg[node].max = max(seg[node].max,seg[L(node)].max);
}
if (mid + 1 <= y)
{
insert(R(node),x,y,d);
seg[node].max = max(seg[node].max,seg[R(node)].max);
}
}
}
int main()
{
freopen( " railway.in " , " r " ,stdin);
freopen( " railway.out " , " w " ,stdout);
scanf( " %ld%ld%ld " , & n, & s, & m);
build( 1 , 1 ,n - 1 );
while (m -- )
{
long a,b,d;
scanf( " %ld%ld%ld " , & a, & b, & d);
if (ok( 1 ,a,b - 1 ,d))
{
printf( " YES\n " );
insert( 1 ,a,b - 1 ,d);
}
else printf( " NO\n " );
}
return 0 ;
}
#define maxn 60007
#define L(x) (x<<1)
#define R(x) ((x<<1)+1)
#define max(a,b) (a>b?a:b)
struct
{
long a,b;
long max,cover;
}seg[maxn * 3 ];
long n,s,m;
void build( long node, long x, long y)
{
long mid = (x + y) >> 1 ;
seg[node].a = x;seg[node].b = y;
seg[node].max = seg[node].cover = 0 ;
if (x < y)
{
build(L(node),x,mid);
build(R(node),mid + 1 ,y);
}
}
bool ok( long node, long x, long y, long d)
{
long a = seg[node].a,b = seg[node].b,mid = (a + b) >> 1 ;
bool re = false ,cal = false ;
if (x <= a && b <= y)
return (seg[node].max + d <= s);
if (seg[node].cover > 0 )
{
seg[L(node)].cover += seg[node].cover;
seg[R(node)].cover += seg[node].cover;
seg[L(node)].max += seg[node].cover;
seg[R(node)].max += seg[node].cover;
seg[node].cover = 0 ;
seg[node].max = max(seg[L(node)].max,seg[R(node)].max);
}
if (mid >= x)
{
re = ok(L(node),x,y,d);
cal = true ;
}
if (mid + 1 <= y)
re = ((re ||! cal) && ok(R(node),x,y,d));
return re;
}
void insert( long node, long x, long y, long d)
{
long a = seg[node].a,b = seg[node].b,mid = (a + b) >> 1 ;
if (x <= a && b <= y)
{
seg[node].max += d;
seg[node].cover += d;
}
else
{
if (mid >= x)
{
insert(L(node),x,y,d);
seg[node].max = max(seg[node].max,seg[L(node)].max);
}
if (mid + 1 <= y)
{
insert(R(node),x,y,d);
seg[node].max = max(seg[node].max,seg[R(node)].max);
}
}
}
int main()
{
freopen( " railway.in " , " r " ,stdin);
freopen( " railway.out " , " w " ,stdout);
scanf( " %ld%ld%ld " , & n, & s, & m);
build( 1 , 1 ,n - 1 );
while (m -- )
{
long a,b,d;
scanf( " %ld%ld%ld " , & a, & b, & d);
if (ok( 1 ,a,b - 1 ,d))
{
printf( " YES\n " );
insert( 1 ,a,b - 1 ,d);
}
else printf( " NO\n " );
}
return 0 ;
}