Loading

CF1930H Interactive Mex Tree

首先这种题肯定是查路径之外的 min,并且排列显然跟搜索序有关。直接想疑似是困难的,先想想简单情况,比如说 uv 的祖先。将树分成几块画出来,会发现链上挂着的一些搜索序介于 [dfnu,dfnv] 之间的点不好用 dfn 处理。而注意到它有两个序列可以用,想想还有什么序是好用的?出栈序!我们发现这些不好处理的点可以用出栈序处理,即查询出栈序在 [1,dfuv1] 之间的点。

而会了这种情况的话一般情况也是好做的,画画就可以发现我们可以把树分成 5 块(并不是分割,有可能有重合)。然后就好做了,注意到题目允许我们 O(nq),那么我们直接暴力做就好了。

#include <bits/stdc++.h>
#define rep(i, l, r) for (int i (l); i <= r; ++ i)
#define rrp(i, l, r) for (int i (r); i >= l; -- i)
#define eb emplace_back
using namespace std;
#define pii pair <int, int>
constexpr int N = 3e5 + 5, B = 1e8 + 1;
inline int rd () {
  int x = 0, f = 1;
  char ch = getchar ();
  while (! isdigit (ch)) {
    if (ch == '-') f = -1;
    ch = getchar ();
  }
  while (isdigit (ch)) {
    x = (x << 1) + (x << 3) + (ch ^ 48);
    ch = getchar ();
  }
  return x * f;
}
int qpow (int x, int y, int P) {
  int ret = 1;
  for (; y; y >>= 1, x = x * x % P) if (y & 1) ret = ret * x % P;
  return ret;
}
int n, q; 
vector <int> e[N];
int dep[N], fat[N];
int dfn[N], t1, dfu[N], t2, id1[N], id2[N];
void dfs (int u, int fa) {
  dep[u] = dep[fa] + 1;
  id1[dfn[u] = ++ t1] = u;
  for (auto v : e[u]) {
    if (v == fa) continue;
    dfs (v, u); fat[v] = u;
  } id2[dfu[u] = ++ t2] = u;
}
int ask1 (int l, int r) {
  if (l > r) return n;
  cout << "? 1 " << l << " " << r << endl;
  int mn; cin >> mn; return mn;
}
int ask2 (int l, int r) {
  if (l > r) return n;
  cout << "? 2 " << l << " " << r << endl;
  int mn; cin >> mn; return mn;
}
int LCA (int u, int v) {
  if (dep[u] < dep[v]) swap (u, v);
  while (dep[u] > dep[v]) u = fat[u];
  if (u == v) return u;
  while (fat[u] != fat[v]) {
    u = fat[u], v = fat[v];
  } return fat[u];
}
void solve () {
  cin >> n >> q;
  rep (i, 1, n) e[i].clear ();
  t1 = t2 = 0;
  rep (i, 2, n) {
    int u, v; cin >> u >> v;
    e[u].eb (v), e[v].eb (u);
  }
  dfs (1, 0);
  rep (i, 1, n) cout << id1[i] << " "; cout << endl;
  rep (i, 1, n) cout << id2[i] << " "; cout << endl;
  rep (i, 1, q) {
    int u, v;
    cin >> u >> v;
    if (dfn[u] > dfn[v]) swap (u, v);
    int d = LCA (u, v);
    if (d == u) {
      int ans = min (min (ask1 (1, dfn[u] - 1), ask1 (dfn[v] + 1, n)), ask2 (1, dfu[v] - 1));
      cout << "! " << ans << endl; cin >> d; continue;
    }
    int sv = v, maxn = 0;
    while (fat[sv] != d) sv = fat[sv];
    for (auto v : e[d]) {
      if (v == fat[d]) continue;
      if (dfu[v] < dfu[sv]) maxn = max (maxn, dfu[v]);
    }
    int ans = min (ask1 (1, dfn[d] - 1), min (min (ask1 (dfn[v] + 1, n), ask2 (1, dfu[u] - 1)), min (ask1 (dfn[u] + 1, dfn[sv] - 1), ask2 (maxn + 1, dfu[v] - 1))));
    cout << "! " << ans << endl; cin >> d;
  }
}
int32_t main () {
  int T; cin >> T;
  for (; T; -- T) solve ();
}

作者:lalaouye

出处:https://www.cnblogs.com/lalaouyehome/p/18739532

版权:本作品采用「114514」许可协议进行许可。

posted @   lalaouye  阅读(2)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示