2021牛客寒假算法基础集训营3 E. 买礼物(线段树、链表思想)

买礼物

https://ac.nowcoder.com/acm/contest/9983/E

Description

图片说明

Solution

一开始的思路是用把2的查询 是否有相同转换成查询 里有多少个不同的数字,用带修莫队/树套树等奇奇怪怪的做法。然而, 的数据范围支撑不了上述 的做法。
于是考虑能否用 的复杂度完成本题。注意到我们可以用链表记录每一个数字上次出现和下次出现的下标,那么实际上对于每一次查询,我们只需要查找 是否在 的范围里面,如果成立,就输出 ,否则输出 。对于每次修改,可以类似于链表删除的思想,如下图:
图片说明
简单的说就是令 ,
那么, ,即上图里面的红线。此时,我们把 设置为很大的数字如 保证不会再影响我们查询最小值的过程。
剩下的就是对于 数组建立线段树,使用区间查询最小和单点修改的操作。

Code

#include<bits/stdc++.h>

typedef long long ll;
using namespace std;

const int N = 1e6 + 5;

int n, m, a[N], last[N], nextz[N], pos[N];

struct node {
  int l, r, mx;
}t[N << 1];
void push_up(int rt) {
  t[rt].mx = min(t[rt << 1].mx, t[rt << 1 | 1].mx);
}
void build(int rt, int l, int r) {
  t[rt].l = l, t[rt].r = r;
  if(l == r) {
    t[rt].mx = nextz[l];
    return ;
  }
  int mid = t[rt].l + t[rt].r >> 1;
  build(rt << 1, l, mid);
  build(rt << 1 | 1, mid + 1, r);
  push_up(rt);
}
void update(int rt, int x, int val) {
  if(t[rt].l == t[rt].r) {
    t[rt].mx = val;
    return ;
  }
  int mid = t[rt].l + t[rt].r >> 1;
  if(x <= mid) {
    update(rt << 1, x, val);
  } else {
    update(rt << 1 | 1, x, val);
  }
  push_up(rt);
}
int query(int rt, int ql, int qr) {
  if(ql <= t[rt].l && qr >= t[rt].r) {
    return t[rt].mx;
  }
  int mid = t[rt].l + t[rt].r >> 1;
  if(qr <= mid) {
    return query(rt << 1, ql, qr);
  } else if(ql > mid) {
    return query(rt << 1 | 1, ql, qr);
  } else {
    return min(query(rt << 1, ql, mid), query(rt << 1 | 1, mid + 1, qr));
  }
}
void solve() {
  cin >> n >> m;
  for(int i = 1; i <= n; i++) {
    cin >> a[i];
    nextz[i] = n + 1, last[i] = 0;
  }
  for(int i = 1; i <= n; i++) {
    if(pos[a[i]]) {
      last[i] = pos[a[i]];
      nextz[last[i]] = i;
      pos[a[i]] = i;
    } else {
      pos[a[i]] = i;
    }
  }
  build(1, 1, n);
  while(m--) {
    int op, l, r; cin >> op;
    if(op == 1) {
      cin >> l;
      int L = last[l], R = nextz[l];
      nextz[L] = R, last[R] = L;
      nextz[l] = 1e9;
      update(1, L, R);
      update(1, l, 1e9);
    } else {
      cin >> l >> r;
      int pos = query(1, l, r); // 找到 [l, r] 里面的 nextz 最小的
      if(pos <= r) {
        cout << 1 << '\n';
      } else {
        cout << 0 << '\n';
      }
    }
  }
}
int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  int T = 1; //cin >> T;
  while(T--) {
    solve();
  }
  return 0;
} 
全部评论

相关推荐

有趣的牛油果开挂了:最近这个阶段收到些杂七杂八的短信是真的烦
点赞 评论 收藏
分享
14 收藏 评论
分享
牛客网
牛客企业服务