比赛描述
输入
输入第一行包含三个用空格隔开的整数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; } } } } */