首页 > 其他分享 >The 2023 ICPC Asia Hangzhou Regional Contest F

The 2023 ICPC Asia Hangzhou Regional Contest F

时间:2024-01-26 16:44:48浏览次数:26  
标签:le Contest int Regional mid Asia kN ch 距离

Link:https://codeforces.com/gym/492111/problem/F

知识点:二分答案,树上问题,RMQ 求 lca

对于查询距离某个点长度不大于某个值的题启发性的题。

才知道题名就是树分块的意思妈的,但是这题数据范围把树分块卡掉了哈哈。

这辈子第一次见到不得不用 RMQ 求 lca 的情况、、、

简述

给定一棵大小为 \(n\) 的树,点有点权 \(w_i\) 且保证点权两两不同,边有边权 \(l_i\)。
给定 \(q\) 次操作,每次操作给定参数 \(x, k\) 询问所有距离 \(x\) 不大于 \(k\) 的点点权和的 \(\operatorname{mex}\),即:\(\operatorname{mex}(\{ w_u | \operatorname{dis}(u, x) \le k \land 1\le u\le n \})\)。
\(1\le n,q\le 5\times 10^5\),\(0\le w_i\le 10^9\),\(1\le l_i\le 10^9\),\(1\le x\le n\),\(0\le k\le 10^{15}\)。
4S,1024MB。

分析

对于此题非常重要的典中典之直径结论:距离树上某点最远的点一定是直径的端点。

发现对于每次询问答案具有单调性,考虑二分枚举 \(mid\) 并检查 \(x\) 距离点权值 \(0\sim mid\) 的点是否均小于等于 \(k\)。

这东西一眼很不可检查的样子,但是可以考虑构建一棵包含点权值 \(0\sim mid\) 的最小的子树,即按顺序枚举点权值 \(0\sim mid\) 对应节点,并将它与之前节点构成的连通块通过唯一的路径连接,则上述检查等价于检查 \(x\) 到子树中所有节点距离是否不大于 \(k\)。

虽然 \(x\) 不一定在这棵子树上,但是由结论+手玩下可知距离 \(x\) 最远的点还是子树直径的端点,仅需检查 \(x\) 与直接两端点的距离是否不大于 \(k\) 即可。

于是考虑先预处理权值为 \(0\sim i\) 的节点组成的子树的直径,按顺序枚举节点并考虑加入对直径的影响,由上述结论可知,新直径要么不变,要么只是一端被替换成新加入的节点,讨论即可维护。

注意这题每次二分答案检查时都需要求距离,若查询距离的复杂度是 \(O(\log n)\) 则总时间复杂度是 \(O(n\log n + q\log^2 n)\) 级别的,过不去。则必须用 RMQ \(O(n\log n)-O(1)\) 地求两点距离。

则总时间复杂度 \(O((n+q)\log n)\) 级别。

代码

//知识点:二分答案,树上问题,RMQ 求 lca
/*
By:Luckyblock
*/
#include <bits/stdc++.h>
#define LL long long
#define pr std::pair
#define mp std::make_pair
const int kN = 5e5 + 10;
//=============================================================
int n, q, a[kN];
int edgenum, head[kN], v[kN << 1], w[kN << 1], ne[kN << 1];
int fa[kN], sz[kN], dep[kN], son[kN], top[kN];
LL dis[kN], dd[kN];

int pos[kN], maxans;
pr <int, int> d[kN];
//=============================================================
inline LL read() {
  LL f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3ll) + (w << 1ll) + (ch ^ '0'); 
  return f * w;
}
void Add(int u_, int v_, int w_) {
  v[++ edgenum] = v_;
  w[edgenum] = w_;
  ne[edgenum] = head[u_];
  head[u_] = edgenum;
}
namespace ST {
  int num, Log2[kN << 1], f[kN << 1][20], fir[kN];
  void Dfs(int u_, int fa_) {
    dep[u_] = dep[fa_] + 1;
    fir[u_] = ++ num;
    f[num][0] = u_;
    for (int i = head[u_]; i; i = ne[i]) {
      int v_ = v[i], w_ = w[i];
      if (v_ == fa_) continue ;
      dis[v_] = dis[u_] + 1ll * w_;
      Dfs(v_, u_);
      f[++ num][0] = u_;
    }
  }
  void Prepare() {
    Dfs(1, 1);
    Log2[1] = 0;
    for (int i = 2; i <= num; ++ i) {
      Log2[i] = Log2[i >> 1] + 1; 
    }
    for (int i = 1; i <= 19; ++ i) {
      for (int j = 1; j + (1 << i) - 1 <= num; ++ j) {
        if (dep[f[j][i - 1]] < dep[f[j + (1 << (i - 1))][i - 1]]) {
          f[j][i] = f[j][i - 1];
        } else {
          f[j][i] = f[j + (1 << (i - 1))][i - 1];
        }
      }
    }
  }
  int Lca(int u_, int v_) {
    int l = fir[u_], r = fir[v_];
    if (l > r) std::swap(l, r);
    int lth = Log2[r - l + 1];
    if (dep[f[l][lth]] < dep[f[r - (1 << lth) + 1][lth]]) {
      return f[l][lth];
    }
    return f[r - (1 << lth) + 1][lth];
  }
  LL Dis(int u_, int v_) {
    return dis[u_] + dis[v_] - 2ll * dis[Lca(u_, v_)];
  }
}
void Init() {
  n = read(), q = read();
  for (int i = 1; i <= n; ++ i) {
    a[i] = read();
    if (a[i] <= n) pos[a[i]] = i;
  }
  for (int i = 1; i < n; ++ i) {
    int u_ = read(), v_ = read(), w_ = read(); 
    Add(u_, v_, w_), Add(v_, u_, w_);
  }
  ST::Prepare();

  for (int i = 0; i <= n; ++ i) {
    if (!pos[i]) {
      maxans = i;
      break;
    }
    if (i == 0) {
      d[i] = mp(pos[i], pos[i]);
      dd[i] = 0;
    } else if (i == 1) {
      d[i] = mp(pos[0], pos[1]);
      dd[i] = ST::Dis(pos[0], pos[1]);
    } else {
      LL d1 = dd[i - 1];
      LL d2 = ST::Dis(pos[i], d[i - 1].first);
      LL d3 = ST::Dis(pos[i], d[i - 1].second);
      dd[i] = std::max(d1, std::max(d2, d3));
      if (dd[i] == d1) d[i] = d[i - 1];
      if (dd[i] == d2) d[i] = mp(d[i - 1].first, pos[i]);
      if (dd[i] == d3) d[i] = mp(d[i - 1].second, pos[i]);
    }
  }
}
bool check(int x_, LL k_, int mid_) {
  LL d1 = ST::Dis(x_, d[mid_].first);
  LL d2 = ST::Dis(x_, d[mid_].second);
  return d1 <= k_ && d2 <= k_;
}
int Query(int x_, LL k_) {
  int ans = maxans;
  for (int l = 0, r = maxans - 1; l <= r; ) {
    int mid = (l + r) >> 1;
    if (check(x_, k_, mid)) {
      l = mid + 1;
    } else {
      ans = mid;
      r = mid - 1;
    }
  }
  return ans;
}
//=============================================================
int main() {
  Init();
  for (int i = 1; i <= q; ++ i) {
    int x = read(); LL k = read(); 
    printf("%d\n", Query(x, k));
  }
  return 0;
}

标签:le,Contest,int,Regional,mid,Asia,kN,ch,距离
From: https://www.cnblogs.com/luckyblock/p/17989696

相关文章

  • AtCoder Beginner Contest 336
    所有代码都在如下模板中运行#include<bits/stdc++.h>usingnamespacestd;namespacegza{ #defineintlonglong #definepbpush_back #defineMTintTTT=R;while(TTT--) #definepcputchar #defineRread() #definefo(i,a,b)for(inti=a;i<=b;i++) #definerep(......
  • contest/1921 E Eat the Chip
    今天在那里吐槽另外一道E题的dp,表示我看不懂。某zz给的建议是:“那就不要做dp”。然后硬着头皮看,还算是看懂了,立刻表示zz是fw。题目的检讨放在U盘里面了,然后不想复制粘贴了。今天上午的模拟题,乱七八糟地骗分,居然有80,某zz只有50分,然后表示zz是fwzz表示,没关系,我改成了100分"....."......
  • 2020-2021 ICPC Southwestern European Regional Contest (SWERC 2020)
    Preface经典前期天胡开局,70min的时候就已经过6题+会另外3题了,本来以为又要像昨天那样提前下班了后面好家伙FGH连着卡,最后磕磕碰碰刚好在结束前写完10个题,强行续上班时长了属于是A.Gratitude签到,注意出现次数相同的字符串的处理#include<cstdio>#include<iostream>#includ......
  • contest/1921 D Very Different Array
    很容易看的出来是一个贪心。首先对A,B数组进行排序。我猜测的结论是每次从A数组和B数组中的两端选择,分别得到:A的最左端-B的最左端的值A的最右端-B的最左端的值A的最左端-B的最右端的值A的最右端-B的最左端的值比较这四个值取最大的然后用双指针维护一下就可以了。......
  • 2020-2021 ICPC NERC (NEERC), North-Western Russia Regional Contest (Northern Sub
    Preface最近事情挺多积压了三天没训练,本来计划着去补CF的题,但后面还是溜去写WA2杂谈了今天重归训练结果碰上超级毒瘤场,2h30min9题后剩下题目都难得飞起,最后还是靠徐神大力切了L题(我早就提前下班了)评价是这就是Russia场的威力吗,后面的Hard题是一点不可做啊A.Archivist纯签到......
  • Xmas Contest 2021 D Determinant?
    由Amitsur-Levitzki定理,当\(n\ge2k\)时,答案为\(0\)矩阵。否则我们考虑答案矩阵的某一位\(b_{i,j}\),其必然由某些路径\(i=p_0\top_1\to\\cdots\top_n=j\)贡献而来,一条路径的贡献为\(\text{sgn}(\sigma)\cdot\prod\limits_{i=1}^nA_{\sigma(i),p_{i-1},p_{i}}\)。......
  • contest/1922 D Berserk Monster
    来来来,看看英语不好的我最开始理解的题目是怎么样的:(1)有一堆怪物在打架,每一次从左到右,一只怪物向离自己最近的怪物攻击一次,每一次怪物都攻击一次后会死掉多少只怪物。怎么做......(2)仔细阅读以后发现可能是所有怪物同时发动攻击。变简单了。(3)再阅读,发现所有怪物被攻击以后,受到的......
  • AtCoder Regular Contest 170 A-C
    A-YetAnotherABProblem贪心。定义下标\(i\)满足\(S[i]=B,T[i]=A\)为\(BA\)型,\(S[i]=B,T[i]=A\)为\(AB\)型,\(AA\)型、\(BB\)型同理。对所有\(BA\)型的下标\(i\)去匹配其右侧的第一个\(AB\)型的下标\(j\),匹配成功则对下标\(i\)和\(j\)进行操作,若无法匹配,则对剩余的\(BA\)型......
  • AtCoder Regular Contest 170 D Triangle Card Game
    洛谷传送门AtCoder传送门赛后调了40min,哈哈。首先先把\(a,b\)排序。考虑先枚举Alice选的数\(a_i\),然后若\(\forallj,\existsk\nei,(a_i,b_j,a_k)\)能组成三角形,Alice就赢了。考虑简化条件。\((x,y,z)\)能形成三角形的充要条件是\(z\in(|x-y|,x+......
  • Toyota Programming Contest 2024#1(AtCoder Beginner Contest 337)
    ToyotaProgrammingContest2024#1(AtCoderBeginnerContest337)A-Scoreboard代码:#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;usingpii=pair<ll,ll>;#definefifirst#definesesecondusingi128=__int128_t;void......