构造线段树 线段树越界问题

题意:饭店有n种菜,每种菜只有一盘,现在有m个人来买菜,每个人买自己能买的最贵的菜。现在有q个操作,每个操作有两种类型:1 i x 表示第i种菜价格变为x,2 i x 表示第i个人拥有的钱变为x。每次操作后询问m个人买菜后所剩的最贵的菜价格。

题解:维护一个区间,例如1 i x就令区间[1,x]加12 i x就令区间[1,x]减1。然后查询正数的最大下标。例如维护多个操作后第k个数为正数,下标k+1后没有正数,则答案是k。

越界问题:本来N是4e6+5,然后RE了,发现是因为pushdown时没有判断l==r,然后改成6e6+5就好了,或者改pushdown也行。

题目链接:http://codeforces.com/contest/1180/problem/E

AC代码:

#include<bits/stdc++.h>
#define N 6000005
#define M 1000005 
using namespace std ;
typedef long long ll ;
int n , m ;
int nm ;
int q ;
int a[N] ;
int b[N] ;
int max1[N] ;
int add[N] ;
bool flag ;
int ans ;
void pushup(int id , int lson , int rson)
{
    max1[id] = max(max1[lson] , max1[rson]) ;
}
void pushdown(int id , int lson , int rson)
{
	add[lson] += add[id] ;
	add[rson] += add[id] ;
	max1[lson] += add[id] ;
	max1[rson] += add[id] ;
	add[id] = 0 ;
}
void update(int s , int id , int l , int r , int x , int y)
{
	int lson = id * 2 ;
	int rson = id * 2 + 1 ;
	int mid = (l + r) / 2 ;
	if(l > r || x > y || x > r || l > y)
	   return ;
	if(x <= l && r <= y)
	{
	    if(s == 1)
	    {
	       add[id] ++ ;
		   max1[id] ++ ;	
		}
	    else
	    {
	       add[id] -- ;
		   max1[id] -- ;	
		}
		return ;
	}
	pushdown(id , lson , rson) ;
	update(s , lson , l , mid , x , y) ;   
	update(s , rson , mid + 1 , r , x , y) ; 
    pushup(id , lson , rson) ;
}
void query(int id , int l , int r)
{
	if(flag)
	   return ; 
	int lson = id * 2 ;
	int rson = id * 2 + 1 ;
	int mid = (l + r) / 2 ;
	pushdown(id , lson , rson) ;
	if(l == r)
	{
		ans = l ;
		flag = 1 ;
		return ;
	}
	if(max1[rson] >= 1)
	  query(rson , mid + 1 , r) ;
	else
	  query(lson , l , mid) ;
    pushup(id , lson , rson) ;
}
int main()
{
	int i , j ;
	int s , x ;
	int temp ;
	memset(max1 , 0 , sizeof(max1)) ;
	memset(add , 0 , sizeof(add)) ;
	scanf("%d%d" , &n , &m) ;
	nm = max(n , m) ;
	for(i = 1 ; i <= n ; i ++)
	{
		scanf("%d" , &a[i]) ;
		update(1 , 1 , 1 , M - 5 , 1 , a[i]) ;
	}	  
	for(i = 1 ; i <= m ; i ++)
	{
		scanf("%d" , &b[i]) ;
		update(2 , 1 , 1 , M - 5 , 1 , b[i]) ;
	}
	scanf("%d" , &q) ;
	while(q --)
	{
		scanf("%d%d%d" , &s , &i , &x) ;
		if(s == 1)
		{
			update(2 , 1 , 1 , M - 5 , 1 , a[i]) ; 
			update(1 , 1 , 1 , M - 5 , 1 , x) ;
			a[i] = x ;
		}
		else
		{
			update(1 , 1 , 1 , M - 5 , 1 , b[i]) ; 
			update(2 , 1 , 1 , M - 5 , 1 , x) ;
			b[i] = x ;
		}
		flag = 0 ;
		if(max1[1] + add[1] <= 0)
			ans = -1 ;
		else
		    query(1 , 1 , M - 5) ;
		printf("%d\n" , ans) ;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值