CodeChef COT5 / SPOJ COT5【线段树】【毒瘤】【动态LCA】

#include <iostream>
#include <cstdio>
#include <map>
#include <set>
#include <iterator>
#include <cctype>

#define int long long

using namespace std;

int cntForDebug = 0;
inline void qwq() {
  cout << "QwQ " << ++ cntForDebug << " Times!\n";
}

set <int> se;
map <int, int> mp;

const int N = 2e5 + 10, INF = -1e9;
struct arrQue {
  int opt, x, y;
} q[N];

int get_integer() {
  char ch;
  int opt = 1, x;
  while (!isdigit(ch = getchar()))
    if (ch == '-')
      opt = -1;
  x = ch ^ '0';
  while (isdigit(ch = getchar()))
    x = (x << 3) + (x << 1) + (ch ^ '0');
  return x * opt;
}

long long get_llinteger() {
  char ch;
  int opt = 1;
  long long x;
  while (!isdigit(ch = getchar()))
    if (ch == '-')
      opt = -1;
  x = ch ^ '0';
  while (isdigit(ch = getchar()))
    x = (x << 3LL) + (x << 1LL) + (ch ^ '0');
  return x * opt;
}

inline void swap(int &x, int &y) {
  int t = x;
  x = y;
  y = t;
}

int tot, n, t, lca;

struct Node {
  int l, r;
  int mx, pre, suf;
} z[N << 2];

void dg(int l, int r, int rt, int nowl, int nowr) {
  if (nowl <= l && r <= nowr) {
    if (t > z[rt].mx)
      return ;
    t = z[rt].mx;
    if (l == r) {
      lca = l;
      return ;
    }
    int mid = l + r >> 1;
    dg(l, mid, rt << 1, nowl, nowr);
    dg(mid + 1, r, rt << 1 | 1, nowl, nowr);
    return ;
  }
  int mid = l + r >> 1;
  if (nowl <= mid)
    dg(l, mid, rt << 1, nowl, nowr);
  if (mid < nowr)
    dg(mid + 1, r, rt << 1 | 1, nowl, nowr);
}

int get_lca(int u, int v) {
  t = 0, lca = 0;
  if (u > v)
    swap (u, v);
  dg(1, tot, 1, u, v);
  return lca;
}

int calc_pre(int l, int r, int rt, int x) {
  if (l == r) {
    if (x < z[rt].mx)
      return 1;
    return 0;
  }
  int mid = l + r >> 1;
  if (x < z[rt << 1].mx)
    return calc_pre(l, mid, rt << 1, x) + z[rt].pre;
  return calc_pre(mid + 1, r, rt << 1 | 1, x);
}

int calc_suf(int l, int r, int rt, int x) {
  if (l == r) {
    if (x < z[rt].mx)
      return 1;
    return 0;
  }
  int mid = l + r >> 1;
  if (x < z[rt << 1 | 1].mx)
    return calc_suf(mid + 1, r, rt << 1 | 1, x) + z[rt].suf;
  return calc_suf(l, mid, rt << 1, x);
}

void update(int l, int r, int rt) {
  int mid = l + r >> 1;
  z[rt].mx = max(z[rt << 1].mx, z[rt << 1 | 1].mx);
  z[rt].pre = calc_pre(mid + 1, r, rt << 1 | 1, z[rt << 1].mx);
  z[rt].suf = calc_suf(l, mid, rt << 1, z[rt << 1 | 1].mx);
}

void modify(int l, int r, int rt, int p, int v) {
  if (l == r) {
    z[rt].mx = v;
    return ;
  }
  int mid = l + r >> 1;
  if (p <= mid)
    modify(l, mid, rt << 1, p, v);
  else
    modify(mid + 1, r, rt << 1 | 1, p, v);
  update(l, r, rt);
}

int query_pre(int l, int r, int rt, int x) {
  if (x <= l) {
    int res = calc_pre(l, r, rt, t);
    t = max(t, z[rt].mx);
    return res;
  }
  int mid = l + r >> 1;
  int res = 0;
  if (x <= mid)
    res += query_pre(l, mid, rt << 1, x);
  res += query_pre(mid + 1, r, rt << 1 | 1, x);
  return res;
}

int query_suf(int l, int r, int rt, int x) {
  if (x >= r) {
    int res = calc_suf(l, r, rt, t);
    t = max(t, z[rt].mx);
    return res;
  }
  int mid = l + r >> 1;
  int res = 0;
  if (x > mid)
    res += query_suf(mid + 1, r, rt << 1 | 1, x);
  res += query_suf(l, mid, rt << 1, x);
  return res;
}

int query(int x) {
  int ans = 0;
  t = 0;
  ans += query_pre(1, tot, 1, x);
  t = 0;
  ans += query_suf(1, tot, 1, x);
  return ans - 1;
}

inline void insert(int k, int w) {
  modify(1, tot, 1, mp[k], w);
}

inline void del(int k) {
  modify(1, tot, 1, mp[k], 0);
}

inline int get_dist(int u, int v) {
  u = mp[u], v = mp[v];
  return query(u) + query(v) - 2 * query(get_lca(u, v));
}

signed main() {
  n = get_llinteger();
  for (int i = 1; i <= n; i ++) {
    q[i].opt = get_llinteger();
    if (q[i].opt == 0)
      q[i].x = get_llinteger(), q[i].y = get_llinteger();
    else if (q[i].opt == 1)
      q[i].x = get_llinteger();
    else
      q[i].x = get_llinteger(), q[i].y = get_llinteger();
  }
  for (int i = 1; i <= n; i ++)
    if (q[i].opt == 0)
      se.insert(q[i].x);
  for (auto &u : se)
    mp[u] = ++ tot;
  for (int i = 1; i <= n; i ++) {
    int &opt = q[i].opt;
    if (opt == 0) {
      int k, w;
      k = q[i].x, w = q[i].y;
      insert(k, w);
    }
    else if (opt == 1) {
      int k;
      k = q[i].x;
      del(k);
    }
    else {
      int u, v;
      u = q[i].x, v = q[i].y;
      cout << get_dist(u, v) << '\n';
    }
  }
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值