hdoj 3627 Giant For

本文详细介绍了线段树算法的应用,通过解决HDU 3627问题为例,讲解了如何利用线段树进行数据的离散化处理,并实现插入、删除及区间查询等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

类型:线段树

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3627

来源: 2010 Asia Regional Tianjin Site —— Online Contest

思路:将读入的数据排序后离散化,以下标为叶子节点建立线段树,叶子节点存储该位置处的列值,非叶子节点存储该区间中叶子的最大列值。然后进行线段树的插入、删除和查找【给定查找区间】

!!!find_i函数位置的确定

!!!查询时的比较

// hdoj 3627 Giant For
// wa ce wa re ac 1609MS 12732K
#include <iostream>
#include <string>
#include <queue>
#include <stack>
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

#define FOR(i,a,b) for(i = (a); i < (b); ++i)
#define FORE(i,a,b) for(i = (a); i <= (b); ++i)
#define FORD(i,a,b) for(i = (a); i > (b); --i)
#define FORDE(i,a,b) for(i = (a); i >= (b); --i)
#define max(a,b) ((a) > (b)) ? (a) : (b)
#define min(a,b) ((a) < (b)) ? (a) : (b)
#define CLR(a,b) memset(a,b,sizeof(a))
#define PB(x) push_back(x)

const int MAXN = 200010;
const int MAXM = 0;
const int hash_size = 25000002;
const int INF = 0x7f7f7f7f;

int n, cnt, cas = 1;
char ch[MAXN][10];
struct node {
    int l, r;
    int max_cal;
}seg_tree[MAXN * 4];
struct data {
    int x, y;
}num[MAXN], st[MAXN], endd[MAXN];

int find_i(int x, int y) {
    int l = 1, r = cnt, mid;
    while(l <= r) {
        mid = (l + r) >> 1;
        //!!!
        if(endd[mid].x > x)
            r = mid - 1;
        else
            l = mid + 1;
    }
    while(--l) {
        if(endd[l].y == y)
            return l;
    }
}

void build(int l, int r, int num) {
    seg_tree[num].l = l;
    seg_tree[num].r = r;
    seg_tree[num].max_cal = 0;
    int mid = (l + r) >> 1;
    if(r > l) {
        build(l, mid, num << 1);
        build(mid + 1, r, (num << 1) | 1);
    }
}

void insert(int i, int num) {
    if(seg_tree[num].l == seg_tree[num].r) {
        seg_tree[num].max_cal = endd[i].y;
        return ;
    }
    int mid = (seg_tree[num].l + seg_tree[num].r) >> 1;
    if(i <= mid)
        insert(i, num << 1);
    else
        insert(i, (num << 1) | 1);
    seg_tree[num].max_cal = max(seg_tree[num << 1].max_cal, seg_tree[(num << 1) | 1].max_cal);
}

void dele(int i, int num) {
    if(seg_tree[num].l == seg_tree[num].r) {
        seg_tree[num].max_cal = 0;
        return ;
    }
    int mid = (seg_tree[num].l + seg_tree[num].r) >> 1;
    if(i <= mid)
        dele(i, num << 1);
    else
        dele(i, (num << 1) | 1);
}

int query(int i, int num, int l, int r) {
    if(seg_tree[num].max_cal <= endd[i].y)
        return -1;
    if(seg_tree[num].l == seg_tree[num].r) {
        //!!!
        if(endd[seg_tree[num].l].x > endd[i].x && seg_tree[num].max_cal > endd[i].y)
            return seg_tree[num].l;
        return -1;
    }
    int ans = -1, mid = (seg_tree[num].l + seg_tree[num].r) >> 1;
    if(l <= mid)
        ans = query(i, num << 1, l, r);
    if(r > mid && ans == -1)
        ans = query(i, (num << 1) | 1, l, r);
    return ans;
}

bool cmp(data a, data b) {
    if(a.x != b.x)
        return a.x < b.x;
    return a.y < b.y;
}

void solve() {
    int i;

    sort(st + 1, st + 1 + n, cmp);
    endd[1].x = st[1].x, endd[1].y = st[1].y;
    cnt = 1;
    FORE(i, 2, n) {
        if(st[i].x == st[i - 1].x && st[i].y == st[i - 1].y)
            continue;
        else
            endd[++cnt] = st[i];
    }
    endd[++cnt].x = INF,  endd[cnt].y = INF;
    build(1, cnt + 1, 1);
    if(cas > 1)
        printf("\n");
    printf("Case %d:\n", cas++);
    FORE(i, 1, n) {
        int t = find_i(num[i].x, num[i].y);
        if(!strcmp(ch[i], "add"))
            insert(t, 1);
        if(!strcmp(ch[i], "remove"))
            dele(t, 1);
        if(!strcmp(ch[i], "find")) {
            int tmp = query(t, 1, t, cnt);
            if(tmp == -1)
                printf("-1\n");
            else
                printf("%d %d\n", endd[tmp].x, endd[tmp].y);
        }
    }
}

void init() {
    int i;

    FORE(i, 1, n) {
        scanf("%s %d %d", ch[i], &num[i].x, &num[i].y);
        st[i].x = num[i].x, st[i].y = num[i].y;
    }
}

int main() {
    while(scanf("%d", &n) == 1, n) {
        init();
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值