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


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

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

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

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

93MS 18212K
用__max一直tle。不知道是不是poj的问题



#include 
#include 
#include 


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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)


你可能感兴趣的:(数据结构,树,结构,数据结构,线段树)