hdu 3627 Giant For //線段樹


首先以x爲第一關鍵字,y爲第二關鍵字進行排序,離散化

得到一個長度爲num的數組(任何一次查詢對應的點都能在這個數組中找到)

對此進行建樹

比如進行第i次操作

找到其在數組中對應的點pos

那麼pos--->num這裏面的所有點的x值都大於等於pos點

看這一段序列是否有值的縱座標大於pos點(還要注意可能會出現x座標相同的情況,這個其實可以通過預處理找到某一段x值都大於pos點的,我懶得寫了)

線段樹維護一個最大的縱座標的值,這個是降低複雜度的關鍵


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL(x)  (x<<1)
#define RR(x)  ((x<<1)|1)
const int MAXN = 200000 + 1234;
struct Seg_Tree
{
    int l, r, vmax;//vamx --> col
    int mid()
    {
        return (l + r) >> 1;
    }
} tree[MAXN * 4];

struct node
{
    int l, r, op, id;
} que[MAXN], tmp[MAXN];
int mark[MAXN];
int remark[MAXN];

bool cmp(node a, node b)
{
    if(a.l == b.l)  return a.r < b.r;//若橫座標相同,則按縱座標從小到大排序
    return a.l < b.l;
}

void build(int l, int r, int idx)
{
    tree[idx].l = l;
    tree[idx].r = r;
    tree[idx].vmax = 0;
    if(l == r) return ;
    int mid = tree[idx].mid();
    build(l, mid, LL(idx));
    build(mid+1, r, RR(idx));
}

void update_info(int idx)
{
    tree[idx].vmax = max(tree[LL(idx)].vmax, tree[RR(idx)].vmax);
}

void insert(int col, int id, int idx)
{
    if(tree[idx].l == tree[idx].r)
    {
        tree[idx].vmax = col;
        return;
    }
    int mid = tree[idx].mid();
    if(id > mid)  insert(col, id, RR(idx));
    else if(id <= mid) insert(col, id, LL(idx));
    update_info(idx);
}

void remove(int id, int idx)
{
    if(tree[idx].l == tree[idx].r)
    {
        tree[idx].vmax = 0;
        return;
    }
    int mid = tree[idx].mid();
    if(id > mid)  remove(id, RR(idx));
    else if(id <= mid) remove(id, LL(idx));
    update_info(idx);
}

int find(int row, int col, int l, int r, int idx)//在l-->r這個區間找一個值大於row和col的
{
    if(tree[idx].vmax <= col)  return -1;
    if(tree[idx].l == tree[idx].r)
    {
        if(que[remark[tree[idx].l]].l > row)
        {
            return remark[tree[idx].l];
        }
        else return -1;
    }

    int mid = tree[idx].mid();
    //儘量找左邊的
    if(l <= mid)
    {
        //int ans = find(row, col, l, mid, LL(idx));這種錯誤不要再犯了!
        int ans = find(row, col, l, r, LL(idx));
        if(ans != -1)  return ans;
    }
    if(r > mid)
    {
        //int ans = find(row, col, mid+1, r, RR(idx));
        int ans = find(row, col, l, r, RR(idx));
        if(ans != -1)  return ans;
    }
    return -1;
}

int main()
{
    int n;
    char str[10];
    int cas = 1;
    while(scanf("%d", &n) != EOF)
    {
        if(n == 0)  break;
        if(cas > 1) printf("\n");

        for(int i = 1; i <= n; i++)
        {
            scanf("%s%d%d", str, &que[i].l, &que[i].r);
            tmp[i].l = que[i].l;
            tmp[i].r = que[i].r;
            tmp[i].id = que[i].id = i;
            if(strcmp(str, "add") == 0)  tmp[i].op = que[i].op = 1;
            else if(strcmp(str, "remove") == 0)  tmp[i].op = que[i].op = 2;
            else if(strcmp(str, "find") == 0)  tmp[i].op = que[i].op = 3;
        }

        //開始離散化
        sort(tmp + 1, tmp + 1 + n, cmp);
        tmp[0].l = -10000;
        tmp[0].r = -10000;
        int num = 0;
        for(int i = 1; i <= n; i++)
        {
            if(tmp[i].l == tmp[i-1].l && tmp[i].r == tmp[i-1].r)
            {
                mark[tmp[i].id] = num;
            }
            else
            {
                ++num;
                mark[tmp[i].id] = num;
                remark[num] = tmp[i].id;
            }
        }

        //離散化完了以後開始建樹
        build(1, num, 1);

        printf("Case %d:\n", cas++);
        for(int i = 1; i <= n; i++)
        {
            if(que[i].op == 1)  insert(que[i].r, mark[que[i].id], 1);
            else if(que[i].op == 2)  remove(mark[que[i].id], 1);
            else
            {
                int ans = find(que[i].l, que[i].r, mark[que[i].id], num, 1);
                if(ans == -1)  printf("-1\n");
                else printf("%d %d\n", que[ans].l, que[ans].r);
            }
        }
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章