HDU 2795 线段树(单点更新 区间查询)

 九野的博客,转载请注明出处:http://blog.csdn.net/acmmmm/article/details/11949847

复制个题意:

题意,给你一个h*w的广告版,往上面贴1*wi的广告,求能够贴上且位置最上,最左的行hi;

解法:每次需找长度>=wi的最上最左位置,然后该位置长度-wi;

线段树data[]存放每个高度现有的宽度,区间找最大值,单点更新。

 

 

#include <cstdio>
#include <cstring>
#include <iostream>
#include <math.h>
#include <queue>
#define N  201000
#define M 2000100
#define inf64 0x7ffffff
#define inf 0x7ffffff
#define ll int
#define L(x) x<<1
#define R(x) x<<1|1
#define Mid(x,y) (x+y)>>1
using namespace std;
inline ll Min(ll a,ll b){return a>b?b:a;}
inline ll Max(ll a,ll b){return a>b?a:b;}

ll len,maxdeep,Query;
struct node{
	int l,r;
	ll sum;
}tree[N*4];

void build(int l,int r,int id){
	tree[id].l = l;	tree[id].r = r;

	tree[id].sum = maxdeep; //
	if(l==r) return ;
	int mid = Mid(l,r);
	build(l,mid,L(id));	 build(mid+1,r,R(id));

}

void updata_point(int pos,int id, ll data){//单点更新
	if(tree[id].l == pos && pos == tree[id].r)
	{	tree[id].sum += data; return ; }

	int mid = Mid(tree[id].l, tree[id].r);

	if(pos <= mid) 		updata_point(pos, L(id), data);
	else				updata_point(pos , R(id), data);

	tree[id].sum = Max( tree[L(id)].sum , tree[R(id)].sum );

}

ll query_point(int pos, int id){ //单点询问
	if(tree[id].l == pos && pos == tree[id].r)
		return tree[id].sum ;

	int mid = Mid(tree[id].l, tree[id].r);

	if(pos <= mid) 		return query_point(pos, L(id));
	else				return query_point(pos, R(id));

}

ll query_inter(int l,int r,int id){
	if( l <= tree[id].l && tree[id].r <= r)
		return tree[id].sum;

	int mid = Mid(tree[id].l , tree[id].r );

	return Max( query_inter( l, r, L(id)) , query_inter( l, r, R(id)));
}
int find_rightmost(int data, int id){
	if(tree[id].l == tree[id].r)return tree[id].l;

	int mid = Mid( tree[id].l,tree[id].r);
	if( query_inter( tree[id].l, mid, L(id)) >=data )return find_rightmost( data, L(id));
	
	return find_rightmost( data, R(id));
}
int main(){
	int n;
	while(~scanf("%d %d %d",&len,&maxdeep,&Query)){
		build(1,Min(len,Query),1);

		while(Query--){
			scanf("%d",&n);

			if(tree[1].sum<n)
			{printf("-1\n");continue;}

			int pos = find_rightmost( n, 1);

			updata_point( pos, 1, -n);

			printf("%d\n",pos);
		}
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值