Fast Arrangement-3577-线段树成段更新

本题超坑爹,先是题意看了半个多小时都不理解样例,后来去找别人的题解才看懂了。

问题是,给k,q 

k是火车最多能运载的人数,q是询问次数

q行 每行两个数a,b  指有一个人要从a站做到b站,是否合法

即,第一次假设列车是从1开始,一直走到尽头(1000000)

当火车遇到一个(a,b)时 ,先查询区间(a,b-1)的值是否小于k(表示列车在这段路上搭载少于k个人),若是,就把区间(a,b-1)的值加1,

如果查询结果大于k,则标明这时火车已经有k个人了,不能上车。

例如 k=2 先 

给(1,3)  可以上 ,此时【1,3-1】区间标记为1 ,(为什么标记到区间b-1?因为在b点人已经下车,所以就没有加1)

给(2,3)可以上,此时【2,2】区间标记为1+1(之间为1)  同时把【2,2】区间以上的父区间都更新为子节点中较大的一个,即如果【2,2】区间已经为2,即满人了,那么【1,3】区间也要是满人了,但是【1,1】区间不属于【2,2】的父区间,仍然可以载人   ()

再给(1,3) 查询到 (1,3)区间的值为2=k,所以这个人不可以上

再给 (4,8) 这个区间是值为0,可以上

以上纯属举例示范,题中保证a<b  ,不会有区间【2,2】;


用的办法自然是线段树的成段更新操作,只不过把  之前的每个节点记录他所代表的区间的区间和,变为,每个节点距离他所代表区间的最大值

也少不了延迟操作,避免超时嘛。

------------------------------------------------------------------

然而如此水的题我也TLE了几个小时,因为本人在vc上敲这个代码,然后vc不支持max()函数,只有个__max(),然后我就用了后者,一直超时,最后发现自己写个max,不用__max  就ac了

93MS18212K
用__max一直tle。不知道是不是poj的问题



#include <cstdio>
#include <cmath>
#include <math.h>


#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std; 
int max(int a,int b)
{
    return a>b?a:b;
} 
const int N =  1000005   ;
int  sum[4*N], add[4*N] ;		//最极端是4N 
void build(int l,int r,int i)    //  线段树的建立;  
{  
    add[i]=0;    
    sum[i]=0;              //  用了lazy思想,提高了效率;  
    if(l==r) return;  
    int mid=(l+r)>>1;  
    build(l,mid,i<<1);  
    build(mid+1,r,i<<1|1);  
}    
void pushDown(int i, int l, int r)		//把i节点的延迟标记传递到左右儿子节点
{
    if(add[i] != 0)
	{
       // int mid = (l + r) >> 1;
        add[i << 1] += add[i];
        sum[i << 1] +=  add[i];  //[l, mid]代表左儿子区间
        add[i << 1 | 1] += add[i];
        sum[i << 1 | 1] +=  add[i];  //[mid + 1, r]代表右儿子区间
        add[i] = 0;
    }
}

void update(int i, int l, int r, int ql, int qr, int val) //更新区间为qlqr,当前区间为l,r,代表当前区间和的节点为i,更新值为val,
{
    if(l > qr || ql > r)		//更新区间不在当前区间内
        return ;
    if(l >= ql && r <= qr)	//要更新的区间把当前区间完全包括,则把当前整个区间+val,然后返回上一层
	{	
        sum[i] += val;
        add[i] += val;
        return ;
    }
    pushDown(i, l, r);			//如果上面没reutrn 表示要往左右儿子区间查询,所以把延迟标记放下去
    int mid = (l + r) >> 1;
    update(i << 1, l, mid, ql, qr, val);
    update(i << 1 | 1, mid + 1, r, ql, qr, val);
    sum[i] = max(sum[i << 1] ,sum[i << 1 | 1]);
}

int query(int i, int l, int r, int ql, int qr)	 //查询区间为qlqr,当前区间为l,r,代表当前区间和的节点为i 
{
    if(l > qr || ql > r)
        return 0;
    if(l >= ql && r <= qr)
        return sum[i];
    pushDown(i, l, r);				//同update
    int mid =( l + r) >> 1;
    return max(query(i << 1, l, mid, ql, qr) 
        , query(i << 1 | 1, mid + 1, r, ql, qr)  );
}
int ans[N+2];
int tm[N+2][2];
int main()
{
    int n,t,k ,a,b,i;
	cin>>t;
	int cnt=1;
	while(t--)
	{
		int ok=0;
		
		scanf("%d %d",&k,&n);
		int maxx=0;	
		for(  i = 1; i <= n; i++)
		{
			scanf("%d %d",&tm[i][0],&tm[i][1]);
			maxx=max(maxx,tm[i][1]);
		}
		//memset(add,0,sizeof(add));
		//memset(sum,0,sizeof(sum));   	
		build(1,maxx,1);    //  线段树的建立,本题中与直接memset效果一样  

		
		for(  i = 1; i <= n; i++)
		{
			a=tm[i][0];
			b=tm[i][1];
			if (query(1,1,maxx,a,b-1)<k)
			{
				ans[++ok]=i;
				update(1, 1, maxx, a, b-1, 1); 
			}
		}
		printf("Case %d:\n",cnt++);
		for(  i = 1; i <= ok; i++)
		{ 
			printf("%d ",ans[i]);
		}
		printf("\n\n");
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值