牛客寒假集训营第三场E线段树+链表

103 阅读2分钟

题目

题目链接

有 n n n个礼物,每个礼物都有一个编号,有两种操作:

  • 拿走位置 i i i的礼物
  • 查询区间[l,r]有没有两个编号相同的礼物

题解

对于每个位置 i i i,维护两个信息:
l a s t [ i ] last[i] last[i]:表示上一个最近的 a i a_i ai​的位置,如果没有置为 0 0 0
n e x t [ i ] next[i] next[i]:表示下一个最近的 a i a_i ai​的位置,如果没有置为 n + 1 n+1 n+1

这样,就形成了一个链表式的结构。

  • 拿走位置 i i i的物品,只需做类似于链表的删除操作即可。
  • 查询区间[l,r]是否有两个物品,也就是查询区间内是否存在 l a s t [ i ] > = l last[i]>=l last[i]>=l。

代码

/*
 * @Author: hesorchen
 * @Date: 2020-07-19 17:00:02
 * @LastEditTime: 2021-02-06 16:34:36
 * @Description: 栽种绝处的花
 */
#include <bits/stdc++.h>
using namespace std;

int a[500010];
int last[500010];
int nxt[500010];
unordered_map<int, int> mp;

struct node
{
    int k, l, r, maxx;
} tr[500010 << 2];

void pushup(int k)
{
    tr[k].maxx = max(tr[k * 2].maxx, tr[k * 2 + 1].maxx);
}
void build(int k, int l, int r)
{
    tr[k].l = l;
    tr[k].r = r;
    if (l == r)
    {
        tr[k].maxx = last[l];
        return;
    }
    int mid = l + r >> 1;
    build(k * 2, l, mid);
    build(k * 2 + 1, mid + 1, r);
    pushup(k);
}

void change(int k, int pos, int w)
{
    if (tr[k].l == tr[k].r && tr[k].l == pos)
    {
        tr[k].maxx = w;
        return;
    }
    int mid = tr[k].l + tr[k].r >> 1;
    if (pos <= mid)
        change(k * 2, pos, w);
    else
        change(k * 2 + 1, pos, w);
    pushup(k);
}

int query(int k, int l, int r)
{
    if (tr[k].l == l && tr[k].r == r)
        return tr[k].maxx;
    int mid = tr[k].l + tr[k].r >> 1;
    if (r <= mid)
        return query(k * 2, l, r);
    else if (l > mid)
        return query(k * 2 + 1, l, r);
    else
        return max(query(k * 2, l, mid), query(k * 2 + 1, mid + 1, r));
}
int main()
{
    int n, q;
    cin >> n >> q;
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    for (int i = 1; i <= n; i++)
    {
        if (mp.count(a[i]))
        {
            last[i] = mp[a[i]];
            mp[a[i]] = i;
        }
        else
        {
            last[i] = 0;
            mp[a[i]] = i;
        }
    }
    mp.clear();
    for (int i = n; i >= 1; i--)
    {
        if (mp.count(a[i]))
        {
            nxt[i] = mp[a[i]];
            mp[a[i]] = i;
        }
        else
        {
            nxt[i] = 0;
            mp[a[i]] = i;
        }
    }
    build(1, 1, n);
    while (q--)
    {
        int opt;
        scanf("%d", &opt);
        if (opt == 1)
        {
            int temp;
            scanf("%d", &temp);
            int pos1 = last[temp];
            int pos2 = nxt[temp];
            nxt[pos1] = nxt[temp];
            last[pos2] = last[temp];//类似于链表的删除操作
            last[temp] = 0;
            change(1, temp, last[temp]);
            if (pos2 >= 1 && pos2 <= n)
                change(1, pos2, last[pos2]);
        }
        else
        {
            int l, r;
            scanf("%d %d", &l, &r);
            if (query(1, l, r) >= l)
                puts("1");
            else
                puts("0");
        }
    }
    return 0;
}