题目大意:有一棵$n(n\leqslant2\times10^5)$个点的树,每个点有点权,所有的点权构成了$0\sim n-1$的排列。$q(q\leqslant2\times10^5)$次操作,操作有两种:

  1. $1\;x\;y:$交换$x$和$y$的点权
  2. $2:$询问$\max\limits_{x,y\in V}\{mex(x\to y)\}$

题解:这个明显具有可二分性(然后我考场上写了一个虚树判链的,复杂度爆炸+没用)。翻看题解知道这道题可以用线段树来维护区间点是否在一条链上,在区间合并的时候枚举一下在两个区间的四个端点中是哪两个端点为大区间的端点,用$LCA$以及$dfn$序判断一下即可。

在最开始判一下树的形态是一条链的情况

卡点:

C++ Code:

  1. #include <algorithm>
  2. #include <cctype>
  3. #include <cstdio>
  4. namespace __IO {
  5. int ch;
  6. inline int read() {
  7. static int x;
  8. while (isspace(ch = getchar())) ; x = ch & 15;
  9. while (isdigit(ch = getchar())) x = x * 10 + (ch & 15);
  10. return x;
  11. }
  12. }
  13. using __IO::read;
  14.  
  15. #define maxn 200010
  16. int head[maxn], cnt;
  17. struct Edge {
  18. int to, nxt;
  19. } e[maxn];
  20. inline void addedge(int a, int b) {
  21. e[++cnt] = (Edge) { b, head[a] }; head[a] = cnt;
  22. }
  23.  
  24. int fa[maxn], sz[maxn], dep[maxn];
  25. int top[maxn], dfn[maxn], idx;
  26. int find(int x) { return x == top[x] ? x : (top[x] = find(top[x])); }
  27. void dfs(int u) {
  28. int son = 0;
  29. dfn[u] = ++idx, sz[u] = 1;
  30. for (int i = head[u], v; i; i = e[i].nxt) {
  31. v = e[i].to;
  32. dep[v] = dep[u] + 1;
  33. dfs(v), sz[u] += sz[v];
  34. if (sz[v] > sz[son]) son = v;
  35. }
  36. if (son) top[son] = u;
  37. }
  38. inline int LCA(int x, int y) {
  39. while (top[x] != top[y]) {
  40. if (dep[top[x]] > dep[top[y]]) x = fa[top[x]];
  41. else y = fa[top[y]];
  42. }
  43. return dep[x] < dep[y] ? x : y;
  44. }
  45.  
  46. int n, m, w[maxn], ret[maxn];
  47.  
  48. inline bool in_sub(int x, int y) {
  49. return (dfn[x] >= dfn[y]) && (dfn[x] < dfn[y] + sz[y]);
  50. }
  51. inline bool in_line(int x, int y, int z) {
  52. static int lca; lca = LCA(x, y);
  53. return in_sub(z, lca) && (in_sub(x, z) || in_sub(y, z));
  54. }
  55. inline bool in_line(int x, int y, int l, int r) {
  56. return in_line(x, y, l) && in_line(x, y, r);
  57. }
  58.  
  59. struct node {
  60. bool line;
  61. int l, r;
  62. inline node() { }
  63. inline node(int __l) : line(true), l(__l), r(__l) { }
  64. inline node(int __l, int __r) : line(true), l(__l), r(__r) { }
  65. inline node(bool __line, int __l, int __r) : line(__line), l(__l), r(__r) { }
  66. static inline node NS() { return node(0, -1, -1); }
  67. inline node operator + (const node &rhs) const {
  68. if (!l || !r) return rhs;
  69. if (!line || !rhs.line) return NS();
  70. const int x = rhs.l, y = rhs.r;
  71. if (in_line(l, r, x, y)) return node(l, r);
  72. if (in_line(l, x, r, y)) return node(l, x);
  73. if (in_line(l, y, x, r)) return node(l, y);
  74. if (in_line(r, x, l, y)) return node(r, x);
  75. if (in_line(r, y, l, x)) return node(r, y);
  76. if (in_line(x, y, l, r)) return node(x, y);
  77. return NS();
  78. }
  79. } I(0, 0, 0);
  80.  
  81. namespace SgT {
  82. node V[maxn << 2];
  83. void build(const int rt, const int l, const int r) {
  84. if (l == r) {
  85. V[rt] = node(ret[l]);
  86. return ;
  87. }
  88. const int mid = l + r >> 1;
  89. build(rt << 1, l, mid), build(rt << 1 | 1, mid + 1, r);
  90. V[rt] = V[rt << 1] + V[rt << 1 | 1];
  91. }
  92.  
  93. int pos;
  94. void __modify(const int rt, const int l, const int r) {
  95. if (l == r) {
  96. V[rt] = node(ret[l]);
  97. return ;
  98. }
  99. const int mid = l + r >> 1;
  100. if (pos <= mid) __modify(rt << 1, l, mid);
  101. else __modify(rt << 1 | 1, mid + 1, r);
  102. V[rt] = V[rt << 1] + V[rt << 1 | 1];
  103. }
  104. void modify(const int __pos) {
  105. pos = __pos;
  106. __modify(1, 0, n - 1);
  107. }
  108.  
  109. node now;
  110. int res;
  111. void __query(int rt, int l, int r) {
  112. if (l == r) {
  113. res = l;
  114. return ;
  115. }
  116. node tmp = now + V[rt << 1];
  117. const int mid = l + r >> 1;
  118. if (tmp.line) {
  119. now = tmp;
  120. __query(rt << 1 | 1, mid + 1, r);
  121. } else __query(rt << 1, l, mid);
  122. }
  123. int query() {
  124. now = I, res = 1;
  125. __query(1, 0, n - 1);
  126. return res;
  127. }
  128. }
  129.  
  130. int ind[maxn];
  131. bool is_line = true;
  132. int main() {
  133. n = read();
  134. for (int i = 1; i <= n; ++i) {
  135. w[i] = read();
  136. ret[w[i]] = top[i] = i;
  137. }
  138. for (int i = 2; i <= n; ++i) {
  139. fa[i] = read();
  140. addedge(fa[i], i);
  141. ++ind[fa[i]], ++ind[i];
  142. if (ind[fa[i]] > 2 || ind[i] > 2) is_line = false;
  143. }
  144. dfs(1);
  145. for (int i = 1; i <= n; ++i) find(i);
  146. SgT::build(1, 0, n - 1);
  147.  
  148. m = read();
  149. while (m --> 0) {
  150. static int op, x, y;
  151. op = read();
  152. if (op == 1) {
  153. x = read(), y = read();
  154. std::swap(ret[w[x]], ret[w[y]]), std::swap(w[x], w[y]);
  155. if (!is_line) SgT::modify(w[x]), SgT::modify(w[y]);
  156. } else printf("%d\n", is_line ? n : SgT::query());
  157. }
  158. return 0;
  159. }

  

[CF1083C]Max Mex的更多相关文章

  1. CF1083C Max Mex 线段树

    题面 CF1083C Max Mex 题解 首先我们考虑,如果一个数x是某条路径上的mex,那么这个数要满足什么条件? 1 ~ x - 1的数都必须出现过. x必须没出现过. 现在我们要最大化x,那么 ...

  2. Codeforces 1083C Max Mex

    Description 一棵\(N\)个节点的树, 每个节点上都有 互不相同的 \([0, ~N-1]\) 的数. 定义一条路径上的数的集合为 \(S\), 求一条路径使得 \(Mex(S)\) 最大 ...

  3. Max Mex

    Max Mex 无法直接处理 可以二分答案! [0,mid]是否在同一个链上? 可以不修改地做了 修改? 能不能信息合并?可以! 记录包含[l,r]的最短链的两端 可以[0,k][k+1,mid]合并 ...

  4. CF 1083 C. Max Mex

    C. Max Mex https://codeforces.com/contest/1083/problem/C 题意: 一棵$n$个点的树,每个点上有一个数(每个点的上的数互不相同,而且构成一个0~ ...

  5. CodeForces 1084 F Max Mex

    Max Mex 题意:问在树上的所有路中mex值最大是多少. 题解: 用线段树维护值. 区间[L,R]意味着 区间[L,R]的数可不可以合并. 重点就是合并的问题了. 首先合法的区间只有3种: 1. ...

  6. CF 526F Max Mex(倍增求LCA+线段树路径合并)

    Max Mex 题目地址:https://codeforces.com/contest/1084/problem/F 然后合并时注意分情况讨论: 参考代码: #include<bits/stdc ...

  7. 【Codeforces 1083C】Max Mex(线段树 & LCA)

    Description 给定一颗 \(n\) 个顶点的树,顶点 \(i\) 有点权 \(p_i\).其中 \(p_1,p_2,\cdots, p_n\) 为一个 \(0\sim (n-1)\) 的一个 ...

  8. 【线段树】【CF1083C】 Max Mex

    Description 给定一棵有 \(n\) 个点的树,每个节点有点权.所有的点权构成了一个 \(0~\sim~n - 1\) 的排列.有 \(q\) 次操作,每次操作 \(1\) 为交换两个点的点 ...

  9. Codeforces 1083C Max Mex [线段树]

    洛谷 Codeforces 思路 很容易发现答案满足单调性,可以二分答案. 接下来询问就转换成判断前缀点集是否能组成一条链. 我最初的想法:找到点集的直径,判断直径是否覆盖了所有点,需要用到树套树,复 ...

随机推荐

  1. DSP5509的RTC实验-第3篇

    1. RTC实时时钟,不在过多介绍,本例程直接调用芯片支持库CSL的库函数,用起来比较简单 main() { CSL_init(); printf ("\nTESTING...\n" ...

  2. Ubuntu配置IP

    Ubuntu网络配置的常用系统,于是我学习研究了Ubuntu网络配置,在这里对大家详细介绍下Ubuntu网络配置应用,希望对大家有用Ubuntu网络配置包含了非常好的翻译和容易使用的架构./etc/n ...

  3. Win10 远程服务器版

    朋友的电脑刚装了1803版的Win10,然后他用KMS_VL_ALL6.9激活了一下,竟然变成了一个奇怪的版本:“远程服务器版”!第一次见这玩意,还真稀罕.帮他研究了一下,发现KMS_VL_ALL在激 ...

  4. JavaWeb(三)——Tomcat服务器(二)

    一.打包JavaWeb应用 在Java中,使用"jar"命令来对将JavaWeb应用打包成一个War包,jar命令的用法如下:

  5. 「Python」matplotlib备忘录

    总结了一下网上现有的资源,得到了一些东西.随手做个备忘. 更多设置见:https://matplotlib.org/users/customizing.html. 导入 import matplotl ...

  6. 接口测试工具postman(六)添加变量(参数化)

    1.添加全局变量并引用 2.通过设置请求前置配置变量 3.在Tests里面,把响应数据设置为变量 4.添加外部文件,引用外部文件中的变量和数据,此种场景就可以执行多次请求 1)配置文件,txt或者cs ...

  7. jmeter获取cookies

    使用场景:登录后,后续的请求操作需获取到JSESSIONID才可进行 1.将jmeter的bin目录下的jmeter.properties文件中的CookieManager.save.cookies= ...

  8. 【WXS全局对象】JSON

    方法: 原型:JSON.stringify( Object ) 说明:将 object 对象转换为 JSON 字符串,并返回该字符串. 返回:[String] 原型:JSON.parse( [Stri ...

  9. github项目切换远程https到ssh通道

    github 切换远程https到ssh通道 github 每个仓库有两类地址:https和ssh通道. https通道获取代码方便,提交过程中每次都需要输入用户名和密码. ssh通道需要提前配置号s ...

  10. c语言中反转字符串的函数strrev(), reverse()

    1.使用string.h中的strrev函数 #include<stdio.h> #include<string.h> int main() { char s[]=" ...