hdu3577-Fast Arrangement 线段树区间覆盖

Fast Arrangement

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 3233    Accepted Submission(s): 922


Problem Description
Chinese always have the railway tickets problem because of its' huge amount of passangers and stations. Now goverment need you to develop a new tickets query system.
One train can just take k passangers. And each passanger can just buy one ticket from station a to station b. Each train cannot take more passangers any time. The one who buy the ticket earlier which can be sold will always get the ticket.
 

Input
The input contains servel test cases. The first line is the case number. In each test case:
The first line contains just one number k( 1 ≤ k ≤ 1000 ) and Q( 1 ≤ Q ≤ 100000 )
The following lines, each line contains two integers a and b, ( 1 ≤ a < b ≤ 1000000 ), indicate a query.
Huge Input, scanf recommanded.
 

Output
For each test case, output three lines:
Output the case number in the first line.
If the ith query can be satisfied, output i. i starting from 1. output an blank-space after each number.
Output a blank line after each test case.
 

Sample Input
  
  
1 3 6 1 6 1 6 3 4 1 5 1 2 2 4
 

Sample Output
  
  
Case 1: 1 2 3 5
  
  
题意:

有一辆火车,人们要上车需要购买车票,但是同一时刻火车上的人数有上限,如果需要购买的车票的时间段内某一时刻人数到达上限则不能上车, 否则就要输出这个人的序号,即可以上车的人序号。


解题思路:

首先利用时刻来构建二叉树,所以注意这里的大小是1000000,由于需要处理区间覆盖,所以一般的方法会超时,在这里我们需要使用延迟标记。然后我们在得到购票的时刻后我们可以先进行查询这个时间段内的最大人数,如果发现人没满就可以上车,同时将这个时间段内的乘车人数都加1,否则就不能上车,即不处理它,如果可以上车的话,我们还可以用一个数组来存储这些能上车的人的序号,方便最后主函数输出,每次有人上车就更新,最后输出之前存储的数组就可以了,具体请看代码。


ac代码:

#include <cstdio> 
#include <iostream>
#include <cstring>
using namespace std;
#define Max 1000005
//#define max(a,b) a>b?a:b /*不能使用定义,因为我使用定义超时,结果发现不能使用这个定义,很坑*/ 
int sum[Max<<2];//记录最大值 
int co[Max<<2];//延迟标记数组 
int k, n, key;
int f[Max];//记录上车人的序号 
int max(int a,int b)//使用C++交题需要自己写max函数,只能这样写,不能定义 
{
	return a>b?a:b;
}
void Build(int l, int r, int rt)//建树 
{
    sum[rt] = 0;
    co[rt] = 0;
    if(l == r) return ;
    int m = (l + r) >> 1;
    Build(l, m, rt<<1);
    Build(m+1, r, rt<<1|1);
    sum[rt] = max(sum[rt<<1], sum[rt<<1|1]);
}
void Updown(int rt)//向下延迟标记 
{
    if(co[rt])
    {
        co[rt<<1] += co[rt];
        co[rt<<1|1] += co[rt];
        sum[rt<<1] += co[rt];
        sum[rt<<1|1] += co[rt];
        co[rt] = 0;
    }
}
void Updata(int L, int R, int l, int r, int rt)//更新 
{
       if(l >= L && r <= R)
       {
           sum[rt] += 1;
           co[rt] += 1;
        return ;
    }
    Updown(rt);
    int m = (l + r) >> 1;
    if(L <= m)  Updata(L, R, l, m, rt<<1);
    if(m < R) Updata(L, R, m+1, r, rt<<1|1);
    sum[rt] = max(sum[rt<<1], sum[rt<<1|1]);
}
int Quest(int L, int R, int l, int r, int rt)//查询 
{
    if(l >= L && r <= R) 
        return sum[rt];
    Updown(rt);
    int ret = 0;
    int m = (l + r) >> 1;
    if(L <= m)  ret = max(ret, Quest(L, R, l, m, rt<<1));
    if(m < R) ret = max(ret, Quest(L, R, m+1, r, rt<<1|1));
    return ret;
}
int main()
{
    int t, a, b, i, j;
    scanf("%d", &t);
    for(j = 1; j <= t; j++)
    {
        int l = 0;
        scanf("%d%d", &k, &n);
        memset(f,0,sizeof(f));
        Build(1, Max, 1);
        for(i = 1; i <= n; i++)
        {
            scanf("%d%d", &a, &b); 
            b--;
            int tt = Quest(a, b, 1, Max, 1);//先查询最大人数,看能不能上车 
            if(tt < k)//人数没满,可以上车 
            {
                f[++l] = i;//记录这个人的序号 
                Updata(a, b, 1, Max, 1);//更新线段树 
            }
        }
        printf("Case %d:\n",j);
        for(i = 1; i <= l; i++)
           printf("%d ",f[i]);
          printf("\n\n");
    }
    return 0;
}

做完这道题之后我觉得以后写max函数还是老老实实用函数写,不要用定义写,还可以选择使用G++交题,可以不用写max函数,因为头文件里包含max函数,如果用C++交题,不写会报错。


题目链接:点击打开链接http://acm.hdu.edu.cn/showproblem.php?pid=3577


相似题目链接:点击打开链接http://blog.csdn.net/wang_heng199/article/details/75044977





  
  
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值