HDU 1823 Luck and Love 二维线段树 / 矩形树

题意:
本题有多个测试数据,第一个数字M,表示接下来有连续的M个操作,当M=0时处理中止。接下来是一个操作符C。当操作符为‘I’时,表示有一个MM报名,后面接着一个整数,H表示身高,两个浮点数,A表示活泼度,L表示缘分值。 (100<=H<=200, 0.0<=A,L<=100.0)当操作符为‘Q’时,后面接着四个浮点数,H1,H2表示身高区间,A1,A2表示活泼度区间,输出符合身高和活泼度要求的MM中的缘分最高值。 (100<=H1,H2<=200, 0.0<=A1,A2<=100.0)所有输入的浮点数,均只有一位小数。

题解:
注意浮点数的处理,一般来说可以离散化,或者化作整数处理。
二维线段树,第一维度的每一个节点都包含第二维度的一颗线段树。这种方式对于更高的维度就不是适用了。这时可用矩形树。

#include <iostream>
using namespace std;

#define N 270
#define M 2100

int lch ( int x ) { return x * 2; }
int rch ( int x ) { return x * 2 + 1; }
int max ( int x, int y ) { return x > y ? x : y; }

struct sonNode
{
    int l, r, val;
    void getlr ( int tl, int tr )
    {
        l = tl; r = tr;
    }
};

struct parentNode
{
    int l, r;
    sonNode son[M];
    void getlr ( int tl, int tr ) 
    {
        l = tl; r = tr;
    }    
};

parentNode node[N];


void sub_build ( int f, int u, int l, int r )
{
    node[f].son[u].getlr ( l, r );
    node[f].son[u].val = -1;
    if ( l == r ) return;
    int mid = ( l + r ) / 2;
    sub_build ( f, lch(u), l, mid );
    sub_build ( f, rch(u), mid+1, r );
}

void build ( int f, int l1, int r1, int l2, int r2 )
{
    node[f].getlr ( l1, r1 );
    sub_build ( f, 1, l2, r2 );
    if ( l1 == r1 ) return;
    int mid = ( l1 + r1 ) / 2;
    build ( lch(f), l1, mid, l2, r2 );
    build ( rch(f), mid+1, r1, l2, r2 );
}

void sub_update ( int f, int u, int pos2, int val )
{
	if ( u > M ) return;   /* 此条件不可忽略 */
    node[f].son[u].val = max ( node[f].son[u].val, val );
	if ( node[f].son[u].l == pos2 && node[f].son[u].r == pos2 )
	{
		node[f].son[u].val = max ( node[f].son[u].val, val );
		return;
	}
    int mid = ( node[f].son[u].l + node[f].son[u].r ) / 2;
    if ( pos2 <= mid )
        sub_update ( f, lch(u), pos2, val );
    else
        sub_update ( f, rch(u), pos2, val );
}

void update ( int f, int pos1, int pos2, int val )
{
	if ( f > N ) return;
    sub_update ( f, 1, pos2, val );
	if ( node[f].l == node[f].r ) return;
    int mid = ( node[f].l + node[f].r ) / 2;
    if ( pos1 <= mid )
        update ( lch(f), pos1, pos2, val );
    else
        update ( rch(f), pos1, pos2, val );
}

int sub_query ( int f, int u, int l2, int r2 )
{    
	if ( u > M ) return -1;  // !!!
    if ( node[f].son[u].l == l2 && node[f].son[u].r == r2 )
        return node[f].son[u].val;
    int mid = ( node[f].son[u].l + node[f].son[u].r ) / 2;
    if ( r2 <= mid )
        return sub_query ( f, lch(u), l2, r2 );
    else if ( l2 > mid )
        return sub_query ( f, rch(u), l2, r2 );
    else
        return max ( sub_query(f,lch(u),l2,mid), sub_query(f,rch(u),mid+1,r2) );
}

int query ( int f, int l1, int r1, int l2, int r2 )
{
	if ( f > N ) return -1;   //!!!
    if ( node[f].l == l1 && node[f].r == r1 )
        return sub_query ( f, 1, l2, r2 );
    int mid = ( node[f].l + node[f].r ) / 2;
    if ( r1 <= mid )
        return query ( lch(f), l1, r1, l2, r2 );
    else if ( l1 > mid )
        return query ( rch(f), l1, r1, l2, r2 );
    else
        return max ( query(lch(f),l1,mid,l2,r2), query(rch(f),mid+1,r1,l2,r2) );
}

int main ()
{
    char ch[3];
    int m, h, hl, hr, ans;
    double a, l, al, ar;
    //freopen("a.txt","r",stdin);
    while ( scanf("%d",&m) != EOF && m )
    {
        memset(node,0,sizeof(node));
        build ( 1, 100, 200, 0, 1000 );
        while ( m-- )
        {    
            scanf("%s",ch);
            if ( ch[0] == 'I' )
            {
                scanf("%d%lf%lf", &h, &a, &l );
                update ( 1, h, (int)(a*10), (int)(l*10) );
            }
            else
            {
                scanf("%d%d%lf%lf", &hl, &hr, &al, &ar);
                if ( hl > hr ) swap ( hl, hr );
                if ( al > ar ) swap ( al, ar );
                ans = query ( 1, hl, hr, (int)(al*10), (int)(ar*10) );
                if ( ans < 0 ) printf("-1\n");
                else printf("%.1lf\n", ans/10.0 );
            }
        }
    }
    return 0;
}



下面是我用矩形树写的,老是超内存,自己不太会优化,没办法了。算学习下算法,就不纠结它了。

#include <algorithm>
#include <cmath>
#include <iostream>
using namespace  std;

#define N 200000
#define eps 0.00001

double bset[N];
int n, size, cnt, tol;

struct tree
{
	int son[4];
	int x1, y1, x2, y2;
	double love;
} node[N*4];

struct operation
{
	int kind;
	double h1, h2, a1, a2, love;
} oper[N];

double max ( double a, double b )
{
	return a > b ? a : b;
}

int bfind ( double key )
{
	int l = 1, r = cnt;
	while ( l <= r )
	{
		int mid = ( l + r ) / 2;
		if ( fabs(bset[mid]-key) < eps )
			return mid;
		if ( bset[mid] > key )
			r = mid - 1;
		else
			l = mid + 1;
	}
	return -1;
}

bool cross( int u, int x1, int y1, int x2, int y2 ) //判断两矩形是否相交
{
    int x3 = node[u].x1;
    int y3 = node[u].y1;
    int x4 = node[u].x2;
    int y4 = node[u].y2;
 
    if ( y2 < y3 || y4 < y1 || x4 < x1 || x2 < x3)
        return false;
    return true;
}

void build ( int x1, int y1, int x2, int y2 ) 
{
	int u = ++tol; /* tol 表示节点编号 */
	node[u].love = -1.0;
	node[u].x1 = x1; node[u].y1 = y1;
	node[u].x2 = x2; node[u].y2 = y2;

	if ( x1 == x2 && y1 == y2 )
		return;

	int midx = ( x1 + x2 ) / 2;
	int midy = ( y1 + y2 ) / 2;

	if ( x1 <= midx && y1 <= midy )   /* 左下方子矩形 */
	{
		node[u].son[0] = tol + 1;
		build ( x1, y1, midx, midy ); 
	}
	else node[u].son[0] = 0;

	if ( midx + 1 <= x2 && midy + 1 <= y2 ) /* 右上方子矩形 */
	{
		node[u].son[1] = tol + 1;
		build ( midx+1, midy+1, x2, y2 ); 
	}
	else node[u].son[1] = 0;

	if ( x1 <= midx && midy + 1 <= y2 ) /*左上方*/
	{
		node[u].son[2] = tol + 1;
		build ( x1, midy + 1, midx, y2 ); 
	}
	else node[u].son[2] = 0;

	if ( midx + 1 <= x2 && y1 <= midy ) /* 右下方 */
	{
		node[u].son[3] = tol + 1;
		build ( midx + 1, y1, x2, midy ); 
	}
	else node[u].son[3] = 0;
}

void update ( int u, int x, int y, double val )
{
	if ( node[u].x1 == node[u].x2 && node[u].y1 == node[u].y2 )
	{
		node[u].love = max ( node[u].love, val );
		return;
	}

	int midx = ( node[u].x1 + node[u].x2 ) / 2;
	int midy = ( node[u].y1 + node[u].y2 ) / 2;
	
	if ( x <= midx )
	{
		if ( y <= midy )
			update ( node[u].son[0], x, y, val );
		else
			update ( node[u].son[2], x, y, val );
	}
	else
	{
		if ( y <= midy )
			update ( node[u].son[3], x, y, val );
		else
			update ( node[u].son[1], x, y, val );
	}

	double temp = -1;
	for ( int i = 0; i < 4; ++i )
		temp = max ( temp, node[node[u].son[i]].love );
	node[u].love = temp;
}

double query ( int u, int x1, int y1, int x2, int y2 )
{
	if ( ! cross(u,x1,y1,x2,y2)  || node[u].love < 0 )
		return -1.0;
	if ( x1 <= node[u].x1 && y1 <= node[u].y1 && node[u].x2 <= x2 && node[u].y2 <= y2 )
		return node[u].love;

	double temp = -1.0;
	for ( int i = 0; i < 4; ++i )
		temp = max ( temp, query ( node[u].son[i], x1, y1, x2, y2) );
	return temp;
}

int main ()
{
	char ch[3];
	int i;
	//freopen("a.txt","r",stdin);
	while ( scanf("%d",&n) != EOF && n )
	{
		size = 0;
		memset(bset,0,sizeof(bset));
		memset(node,0,sizeof(node));
		memset(oper,0,sizeof(oper));
		for ( i = 1; i <= n; ++i )
		{
			scanf("%s",ch);
			if ( ch[0] == 'I' )
			{
				oper[i].kind = 0;
				scanf("%lf%lf%lf", &oper[i].h1, &oper[i].a1, &oper[i].love );
				bset[++size] = oper[i].h1;
				bset[++size] = oper[i].a1;
			}
			else
			{
				oper[i].kind = 1;
				scanf("%lf%lf%lf%lf", &oper[i].h1, &oper[i].h2, &oper[i].a1, &oper[i].a2 );
				bset[++size] = oper[i].h1;
				bset[++size] = oper[i].h2;
				bset[++size] = oper[i].a1;
				bset[++size] = oper[i].a2;
			}
		}
		sort ( bset+1, bset+size+1 );

		for ( cnt = i = 1; i <= size; ++i ) /* 离散化 */
		{
			if ( bset[cnt] != bset[i] )
				bset[++cnt] = bset[i];
		}

		tol = 0;
		build ( 1, 1, cnt, cnt ); 
		
		for ( i = 1; i <= n; ++i )
		{
			if ( oper[i].kind == 0 )
			{
				int x = bfind ( oper[i].h1 );
				int y = bfind ( oper[i].a1 );
				update ( 1, x, y, oper[i].love );
			}
			else
			{
				int x1 = bfind ( oper[i].h1 );
				int x2 = bfind ( oper[i].h2 );
				int y1 = bfind ( oper[i].a1 );
				int y2 = bfind ( oper[i].a2 );
				if ( x1 > x2 ) swap(x1,x2);
				if ( y1 > y2 ) swap(y1,y2);
				double ans =  query ( 1, x1, y1, x2, y2 );
				if ( ans < 0 )
					printf("-1\n");
				else
				    printf ("%.1lf\n", ans );
			}
		}
	}
	return 0;
}




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值