HDU - 1823 Luck and Love(二维线段树查询矩阵最值,树套树与四叉树 + 单点修改,区间查询)

Luck and Love

世界上上最远的距离不是相隔天涯海角 
而是我在你面前 
可你却不知道我爱你 
                ―― 张小娴 

前段日子,枫冰叶子给Wiskey做了个征婚启事,聘礼达到500万哦,天哪,可是天文数字了啊,不知多少MM蜂拥而至,顿时万人空巷,连扫地的大妈都来凑热闹来了。―_―||| 
由于人数太多,Wiskey实在忙不过来,就把统计的事情全交给了枫冰叶子,自己跑回家休息去了。这可够枫冰叶子忙的了,他要处理的有两类事情,一是得接受MM的报名,二是要帮Wiskey查找符合要求的MM中缘分最高值。 

Input

本题有多个测试数据,第一个数字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)
所有输入的浮点数,均只有一位小数。 

Output

对于每一次询问操作,在一行里面输出缘分最高值,保留一位小数。 
对查找不到的询问,输出-1。 

Sample Input

8
I 160 50.5 60.0
I 165 30.0 80.5
I 166 10.0 50.0
I 170 80.5 77.5
Q 150 166 10.0 60.0
Q 166 177 10.0 50.0
I 166 40.0 99.9
Q 166 177 10.0 50.0
0

Sample Output

80.5
50.0
99.9

先分享坑点:坑点1:给出的H,A是可以重复的,所以update时取max, 坑点2:查询的时候给出的 H1,H2,A1,A2不一定满足 H1 <= H1 && A1 <= A2.,坑点3:如果用double开数组然后离散,可能会有精度问题,这里我使用 double读入然后 *10 转为int

 

首先上四叉树的吧。四叉树我一开始一直MLE,然后搜了一下题解,题解都是开的 [5000][5000 << 2] 的空间,但是能过,表示很懵。。然后在队友的帮助下,debug出来发现是递归太深了,最后改出了bug,但是还是不明白为什么。。有大佬可以解答一下。

先贴上有bug的一部分代码:。。请看以下代码。

void update(int xl,int xr,int yl,int yr,int posx,int posy,int i,short val,int dep){
    if(xl > xr || yl > yr) return ;
    if(xl == xr && yl == yr){   /// 若此if语句该成 if(xl == xr && yl == yr && xl == posx && yl == posy) 便递归爆栈了,原因不明
        maxx[i] = max(maxx[i],val);
        return ;
    }
    int midx = (xl + xr) >> 1,midy = (yl + yr) >> 1;
    if(posx <= midx && posy <= midy) update(xl,midx,yl,midy,posx,posy,son(0),val,dep + 1);
    else if(posx <= midx && posy > midy) update(xl,midx,midy + 1,yr,posx,posy,son(1),val,dep + 1);
    else if(posx > midx && posy <= midy) update(midx + 1,xr,yl,midy,posx,posy,son(2),val,dep + 1);
    else if(posx > midx && posy > midy) update(midx + 1,xr,midy + 1,yr,posx,posy,son(3),val,dep + 1);
    push_up(xl,xr,yl,yr,i);
}

 

四叉树AC代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define clr(a,b) memset((a),b,sizeof(a))

using namespace std;
#define son(x) (i * 4 - 2 + x)
const int M = 210;
const int maxn = 1000 * 5000 * 1.5;
short maxx[maxn];

void push_up(int xl,int xr,int yl,int yr,int i){
    maxx[i] = maxx[son(0)];
    if(yl < yr) maxx[i] = max(maxx[i],maxx[son(1)]);
    if(xl < xr) maxx[i] = max(maxx[i],maxx[son(2)]);
    if(xl < xr && yl < yr)
        maxx[i] = max(maxx[i],maxx[son(3)]);
}

void update(int xl,int xr,int yl,int yr,int posx,int posy,int i,short val,int dep){
    if(xl > xr || yl > yr) return ;
    if(xl == xr && yl == yr){
        maxx[i] = max(maxx[i],val);
        return ;
    }
    int midx = (xl + xr) >> 1,midy = (yl + yr) >> 1;
    if(posx <= midx && posy <= midy) update(xl,midx,yl,midy,posx,posy,son(0),val,dep + 1);
    else if(posx <= midx && posy > midy) update(xl,midx,midy + 1,yr,posx,posy,son(1),val,dep + 1);
    else if(posx > midx && posy <= midy) update(midx + 1,xr,yl,midy,posx,posy,son(2),val,dep + 1);
    else if(posx > midx && posy > midy) update(midx + 1,xr,midy + 1,yr,posx,posy,son(3),val,dep + 1);
    push_up(xl,xr,yl,yr,i);
}

short query(int xl,int xr,int yl,int yr,int qxl,int qxr,int qyl,int qyr,int i,int dep){
    if(xl > xr || yl > yr)
        return -1;
    if(xl > qxr || qxl > xr || yl > qyr || qyl > yr)
        return -1;
    if(qxl <= xl && xr <= qxr && qyl <= yl && yr <= qyr)
        return maxx[i];
    int midx = (xl + xr) >> 1,midy = (yl + yr) >> 1;
    short ans = -1;
    if(qxl <= midx && qyl <= midy)
        ans = max(ans,query(xl,midx,yl,midy,qxl,qxr,qyl,qyr,son(0),dep + 1));
    if(qxl <= midx && qyr > midy)
        ans = max(ans,query(xl,midx,midy + 1,yr,qxl,qxr,qyl,qyr,son(1),dep + 1));
    if(qxr > midx && qyl <= midy)
        ans = max(ans,query(midx + 1,xr,yl,midy,qxl,qxr,qyl,qyr,son(2),dep + 1));
    if(qxr > midx && qyr > midy)
        ans = max(ans,query(midx + 1,xr,midy + 1,yr,qxl,qxr,qyl,qyr,son(3),dep + 1));
    return ans;
}

int main() {
    int m;
    double tttt,qqqq;
    int H,A,A1,A2,H1,H2;
    short L,ans;
    while(~scanf("%d",&m) && m){
        clr(maxx,-0x3f);
        for(int i = 1;i <= m;++ i){
            char op; scanf(" %c",&op);
            if(op == 'I'){
                scanf("%d%lf%lf",&H,&tttt,&qqqq);
                A = (int)(tttt * 10);
                L = (short)(qqqq * 10);
                update(1,200,1,1000,H,A,1,L,0);
            }
            else {
                scanf("%d%d%lf%lf",&H1,&H2,&tttt,&qqqq);
                if(H1 > H2) swap(H1,H2);
                A1 = (int)(tttt * 10);
                A2 = (int)(qqqq * 10);
                if(A1 > A2) swap(A1,A2);
                ans = query(1,200,1,1000,H1,H2,A1,A2,1,0);
                if(ans == -1)
                    printf("-1\n");
                else printf("%.1f\n",(double)ans * 1.0 / 10);
            }
        }
    }
    return 0;
}

然后就是树套树,树套树得注意 update 的部分,即

!!! subupdate含 f 标志
void subupdate(int yl,int yr,int posy,int fa_i,int i,int val,int f){
    if(yl == yr){
        if(f) maxx[fa_i][i] = max(maxx[fa_i][i],val);  ///满足 f 是更新val
        else maxx[fa_i][i] = max(maxx[fa_i << 1][i],maxx[fa_i << 1 | 1][i]); ///否则是push_up。而且push_up的是x轴的
    }
    else {
        int mid = (yl + yr) >> 1;
        if(posy <= mid) subupdate(yl,mid,posy,fa_i,ls,val,f);
        if(posy > mid) subupdate(mid + 1,yr,posy,fa_i,rs,val,f);
        maxx[fa_i][i] = max(maxx[fa_i][ls],maxx[fa_i][rs]);
    }
}

void update(int xl,int xr,int yl,int yr,int posx,int posy,int i,int val){
    if(xl == xr){
        subupdate(yl,yr,posy,i,1,val,1); ///!!! 此处f == 1
        return ;
    }
    int mid = (xl + xr) >> 1;
    if(posx <= mid) update(xl,mid,yl,yr,posx,posy,ls,val);
    if(posx > mid) update(mid + 1,xr,yl,yr,posx,posy,rs,val);
    subupdate(yl,yr,posy,i,1,val,0);  ///!!! 此处 f == 0
}

树套树AC代码:

#include<bits/stdc++.h>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#define INT(t) int t; scanf("%d",&t)

using namespace std;

const int maxn = 1010;
const int inf = 0x3f3f3f3f;
int maxx[800][4000];

void subupdate(int yl,int yr,int posy,int fa_i,int i,int val,int f){
    if(yl == yr){
        if(f) maxx[fa_i][i] = max(maxx[fa_i][i],val);
        else maxx[fa_i][i] = max(maxx[fa_i << 1][i],maxx[fa_i << 1 | 1][i]);
    }
    else {
        int mid = (yl + yr) >> 1;
        if(posy <= mid) subupdate(yl,mid,posy,fa_i,ls,val,f);
        if(posy > mid) subupdate(mid + 1,yr,posy,fa_i,rs,val,f);
        maxx[fa_i][i] = max(maxx[fa_i][ls],maxx[fa_i][rs]);
    }
}

void update(int xl,int xr,int yl,int yr,int posx,int posy,int i,int val){
    if(xl == xr){
        subupdate(yl,yr,posy,i,1,val,1);
        return ;
    }
    int mid = (xl + xr) >> 1;
    if(posx <= mid) update(xl,mid,yl,yr,posx,posy,ls,val);
    if(posx > mid) update(mid + 1,xr,yl,yr,posx,posy,rs,val);
    subupdate(yl,yr,posy,i,1,val,0);
}

int subquery(int yl,int yr,int qyl,int qyr,int fa_i,int i){
    if(qyl <= yl && yr <= qyr){
        return maxx[fa_i][i];
    }
    int ans = -1;
    int mid = (yl + yr) >> 1;
    if(qyl <= mid)
        ans = max(ans,subquery(yl,mid,qyl,qyr,fa_i,ls));
    if(qyr > mid)
        ans = max(ans,subquery(mid + 1,yr,qyl,qyr,fa_i,rs));
    return ans;
}

int query(int xl,int xr,int yl,int yr,int qxl,int qxr,int qyl,int qyr,int i){
    if(qxl <= xl && xr <= qxr){
        return subquery(yl,yr,qyl,qyr,i,1);
    }
    int ans = -1;
    int mid = (xl + xr) >> 1;
    if(qxl <= mid)
        ans = max(ans,query(xl,mid,yl,yr,qxl,qxr,qyl,qyr,ls));
    if(qxr > mid)
        ans = max(ans,query(mid + 1,xr,yl,yr,qxl,qxr,qyl,qyr,rs));
    return ans;
}

int main() {
    int m;
    double tttt,qqqq;
    int H,A,A1,A2,H1,H2;
    int L,ans;
    while(~scanf("%d",&m) && m){
        clr(maxx,-0x3f);
        for(int i = 1;i <= m;++ i){
            char op; scanf(" %c",&op);
            if(op == 'I'){
                scanf("%d%lf%lf",&H,&tttt,&qqqq);
                A = (int)(tttt * 10);
                L = (int)(qqqq * 10);
                update(1,200,1,1000,H,A,1,L);
            }
            else {
                scanf("%d%d%lf%lf",&H1,&H2,&tttt,&qqqq);
                if(H1 > H2) swap(H1,H2);
                A1 = (int)(tttt * 10);
                A2 = (int)(qqqq * 10);
                if(A1 > A2) swap(A1,A2);
                ans = query(1,200,1,1000,H1,H2,A1,A2,1);
                if(ans == -1)
                    printf("-1\n");
                else printf("%.1f\n",(double)ans * 1.0 / 10);
            }
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值