南邮 OJ 1409 售票系统

售票系统

时间限制(普通/Java) :  1000 MS/ 3000 MS          运行内存限制 : 65536 KByte
总提交 : 252            测试通过 : 38 

比赛描述

某次列车途经C个城市,城市编号依次为1到C,列车上共有S个座位,铁路局规定售出的车票只能是坐票,即车上所有的旅客都有座,售票系统是由计算机执行的,每一个售票申请包含三个参数,分别用O、D、N表示,O为起始站,D为目的地站,N为车票张数,售票系统对该售票申请作出受理或不受理的决定,只有在从O到D的区段内列车上都有N个或N个以上的空座位时该售票申请才被受理,请你写一个程序,实现这个自动售票系统。


输入

输入第一行包含三个用空格隔开的整数C、S和R,其中1<=C<=60000,1<=S<=60000,1<=R<=60000,C为城市个数,S为列车上的座位数,R为所有售票申请总数。接下来的R行每行为一个售票申请,用三个由空格隔开的整数O,D和N表示,O为起始站,D为目的地站,N为车票站数,其中1<=0<D<=C,1<=N<=C,所有的售票申请按申请的时间从早到晚给出。

输出

输出共有R行,每行输出一个“YES”或“NO”,表示当前的售票申请被受理或不被受理。

样例输入

4 6 4
1 4 2
1 3 2
2 4 3
1 2 3

样例输出

YES
YES
NO
NO

提示

 

题目来源

JSOI2010




#include<stdio.h>
#define MAX_N 60010

struct TreeNode{
	int left;		//最左边线段编号
	int right;		//最右端线段编号
	int maxUsed;	//本跨度线段最多被使用的次数
	int childToAdd;	//本节点已经加过,但是孩子节点没有被加过,等待查询时加的使用计数
}nodes[MAX_N<<2];	//4倍容量肯定够存储

//构建以节点i为根节点的树
void build(int i, int left, int right){
	nodes[i].left = left;
	nodes[i].right = right;
	nodes[i].maxUsed = 0;
	nodes[i].childToAdd = 0;
	if(left != right){
		int mid = (left+right)>>1;
		build(i<<1|1, left, mid);
		build((i+1)<<1, mid+1, right);
	}
}

//[left,right]区间使用计数增加used,更新树
void add(int i, int left, int right, int used){
	if(nodes[i].left==left && nodes[i].right==right){
		nodes[i].maxUsed += used;
		nodes[i].childToAdd += used;		//先存着,向孩子插入时 或者 查询时更新
	}else{
		int lChild = i<<1|1;
		int rChild = (i+1)<<1;
		int temp = nodes[i].childToAdd;		//插入子节点之前,先将childToAdd加到孩子节点
		if(temp){
			nodes[lChild].maxUsed += temp;
			nodes[lChild].childToAdd += temp;
			nodes[rChild].maxUsed += temp;
			nodes[rChild].childToAdd += temp;
			nodes[i].childToAdd = 0;
		}
		int mid = (nodes[i].left+nodes[i].right)>>1;
		if(mid>=left){						//RE 需要更新左子树
			temp = right;
			if(temp>mid){
				temp = mid;
			}
			add(lChild, left, temp, used);
		}
		if(mid+1<=right){					//RE 需要更新右子数
			temp = left;
			if(temp<mid+1){
				temp = mid+1;
			}
			add(rChild, temp, right, used);
		}
		if(nodes[lChild].maxUsed<nodes[rChild].maxUsed){
			nodes[i].maxUsed = nodes[rChild].maxUsed;
		}else{								//更新完子树之后,更新当前节点最大使用次数
			nodes[i].maxUsed = nodes[lChild].maxUsed;
		}
	}
}

//查询[left,right]中最大使用次数
int maxUsed(int i, int left, int right){
	if(nodes[i].left==left && right==nodes[i].right){
		return nodes[i].maxUsed;
	}
	int lChild = i<<1|1;
	int rChild = (i+1)<<1;
	int temp = nodes[i].childToAdd;			//查询子节点之前,先将childToAdd加到孩子节点
	if(temp){
		nodes[lChild].maxUsed += temp;
		nodes[lChild].childToAdd += temp;
		nodes[rChild].maxUsed += temp;
		nodes[rChild].childToAdd += temp;
		nodes[i].childToAdd = 0;
	}
	int mid = (nodes[i].left+nodes[i].right)>>1;
	if(mid>=right){							//区间包含在左子树之内
		return maxUsed(lChild, left, right);
	}
	if(mid+1<=left){						//区间包含在右子树之内
		return maxUsed(rChild, left, right);
	}
	int result = maxUsed(lChild, left, mid);
	temp = maxUsed(rChild, mid+1, right);
	if(result<temp){
		result = temp;
	}
	return result;
}


int main(){
	int C,S,R,O,D,N;
	scanf("%d%d%d",&C,&S,&R);
	build(0,1,C-1);							//第一段路编号1,最后一段路编号C-1,共C-1段路,C个站点
	while(R--){
		scanf("%d%d%d",&O,&D,&N);
		if(maxUsed(0,O,D-1)+N<=S){
			printf("YES\n");
			add(0,O,D-1,N);
		}else{
			printf("NO\n");
		}
	}
}






/*Time Limit Exceed at Test 11
#include<stdio.h>
int a[60001];
int main(){
	int C,S,R,O,D,N,i;
	scanf("%d%d%d",&C,&S,&R);
	for(i=1;i<=C;i++){
		a[i] = S;
	}
	while(R--){
		scanf("%d%d%d",&O,&D,&N);
		for(i=O;i<D;i++){
			if(a[i]<N){
				break;
			}
		}
		if(i<D){
			printf("NO\n");
		}else{
			printf("YES\n");
			for(i=O;i<D;i++){
				a[i] -= N;
			}
		}
	}
}
*/





你可能感兴趣的:(ACM,售票系统,南邮OJ)