Description

一棵\(N\)个节点的树, 每个节点上都有 互不相同的 \([0, ~N-1]\) 的数。

定义一条路径上的数的集合为 \(S\), 求一条路径使得 \(Mex(S)\) 最大。

带修改, \(M\) 次查询

Solution

用一棵权值线段树维护。

节点 \([L,R]\)存储信息:是否有一条路径包含 \([L,R]\) 内的所有数 以及 路径两个端点。

合并两个区间: 在\(4\)个点中 枚举新路径的端点, 然后判断另外两个点是否在路径上即可。

正解能 \(O(1)\) 合并, 然而这个解法需要\(O(logN)\)

所以总复杂度为 \(O(Nlog^2N)\)

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define up(a, b) (a = a > b ? a : b)
#define down(a, b) (a = a > b ? b : a)
#define cmax(a, b) (a > b ? a : b)
#define cmin(a, b) (a > b ? b : a)
#define Abs(a) ((a) > 0 ? (a) : -(a))
#define rd read()
#define db double
#define LL long long
using namespace std;
typedef pair<int, int> P; inline char nc(){
static char buf[1<<14],*p1=buf,*p2=buf;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
char c=nc();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=nc();}
while(c>='0'&&c<='9'){x=x*10+c-'0',c=nc();}
return x*f;
}
const int N = 2e5 + 5; int n, m, a[N], b[N], f[N][20], dep[N];
int timer, tin[N], tout[N]; vector<int> to[N]; void dfs(int u) {
tin[u] = ++timer; // dfs序
for (int i = 0, up = to[u].size(); i < up; ++i) {
int nt = to[u][i];
if (nt == f[u][0])
continue;
dep[nt] = dep[u] + 1;
dfs(nt);
}
tout[u] = timer;
} inline bool isanc(int u, int v) { // 判断u是否是v的祖先
return tin[u] <= tin[v] && tout[u] >= tout[v];
} int getlca(int u, int v) {
if (isanc(u, v))
return u;
for (int i = 19; ~i; --i)
if (f[u][i] && (!isanc(f[u][i], v)))
u = f[u][i];
return f[u][0];
} inline bool isondownpath(int u, P v) { //判断u是否是 竖直路径v() 上的点
return isanc(v.first, u) && isanc(u, v.second);
} inline bool isonpath(int u, P v) { //判断u是否是 路径v()上的点
int lca = getlca(v.first, v.second);
return isondownpath(u, P(lca, v.second)) || isondownpath(u, P(lca, v.first));
} P merge(P u, P v) { //合并两条路径
if (u.first == -1 || v.first == -1)
return P(-1, -1);
int g[4] = {u.first, u.second, v.first, v.second};
for (int i = 0; i < 4; ++i) {
for (int j = i + 1; j < 4; ++j) {
bool flag = true;
for (int k = 0; k < 4; ++k) {
if (k != i && k != j && !isonpath(g[k], P(g[i], g[j])))
flag = false;
}
if (flag)
return P(g[i], g[j]);
} }
return P(-1, -1);
} namespace SegT {
#define mid ((l + r) >> 1)
#define lson u << 1
#define rson u << 1 | 1
P t[N << 2]; void build(int l, int r, int u) {
if (l == r) {
t[u].first = t[u].second = b[l];
return;
}
build(l, mid, lson); build(mid + 1, r, rson);
t[u] = merge(t[lson], t[rson]);
} void update(int c, int l, int r, int u) {
if (l == r) {
t[u].first = t[u].second = b[l];
return;
}
if (c <= mid)
update(c, l, mid, lson);
else update(c, mid + 1, r, rson);
t[u] = merge(t[lson], t[rson]);
} int query(int l, int r, int u, P tmp) {
if (l == r) {
if (tmp.first == -1)
return t[u].first != -1;
P g = merge(tmp, t[u]);
return g.first != -1;
}
P g = tmp.first == -1 ? t[lson] : merge(tmp, t[lson]);
if (g.first == -1)
return query(l, mid, lson, tmp);
else return mid - l + 1 + query(mid + 1, r, rson, g);
}
}using namespace SegT; int main()
{
n = rd;
for (int i = 1; i <= n; ++i)
a[i] = rd + 1, b[a[i]] = i;
for (int i = 2; i <= n; ++i) {
int u = rd;
f[i][0] = u;
to[u].push_back(i);
to[i].push_back(u);
}
dep[1] = 1; dfs(1);
for (int i = 1; i < 20; ++i)
for (int j = 1; j <= n; ++j)
f[j][i] = f[f[j][i - 1]][i - 1];
;
build(1, n, 1);
m = rd;
for (; m; --m) {
int typ = rd;
if (typ == 1) {
int u = rd, v = rd;
swap(a[u], a[v]);
swap(b[a[u]], b[a[v]]); update(a[u], 1, n, 1);
update(a[v], 1, n, 1);
}
else printf("%d\n", query(1, n, 1, P(-1, -1)));
}
}

Max Mex

Codeforces 1083C Max Mex的更多相关文章

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

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

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

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

  3. CodeForces 1084 F Max Mex

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

  4. CF 1083 C. Max Mex

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

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

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

  6. Max Mex

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

  7. CF1083C Max Mex 线段树

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

  8. [CF1083C]Max Mex

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

  9. codeforces#1139E. Maximize Mex(逆处理,二分匹配)

    题目链接: http://codeforces.com/contest/1139/problem/E 题意: 开始有$n$个同学和$m$,每个同学有一个天赋$p_{i}$和一个俱乐部$c_{i}$,然 ...

随机推荐

  1. (24/24) webpack小案例--自己动手用webpack构建一个React的开发环境

    通过前面的学习,对webpack有了更深的认识,故此节我们就利用前面相关知识自己动手用webpack构建一个React的开发环境,就算是一个小案例吧. 注:此处使用的开发工具是Webstorm. 1. ...

  2. Oracle所有分析函数<转>

    Oracle分析函数——函数列表 SUM        :该函数计算组中表达式的累积和 MIN        :在一个组中的数据窗口中查找表达式的最小值 MAX        :在一个组中的数据窗口中 ...

  3. 学习使用github

    自己尝试了一下用git bash完成了第一次下载与上传,感觉git desktop应该是讲bash某些需要输入代码的工作图形化了,但是因为感觉用起来有些不知所措,所以反倒是用代码的gitbash比较方 ...

  4. win10关不了机解决办法以及win10怎么禁止开机启动项

    1.win10关不了机解决办法:https://zhidao.baidu.com/question/693962749213927924.html 2.win10怎么禁止开机启动项:https://j ...

  5. frist Django app — 三、 View

    前面已经说过了Django中model的一些用法,包括orm,以及操作的api,接下来就是搭一些简单的界面学习view——Django中的view.主要介绍以下两个方面: url映射 请求处理 模板文 ...

  6. 关于web前端base64转换为Blob,存入数组后 ajax请求传输到后端 接受不到文件问题

    前端console输出是正常Blob对象,通过ajax formdata 传输到 后端java SpringMvc用MultipartFile接受却一直接受不到,后来直接解析HttpServletRe ...

  7. 用EventEmitter收发消息

    下面简单介绍其步骤. <发消息 方> 1.import进EventEmitter import { EventEmitter } from '@angular/core'; 2.在Comp ...

  8. gridcontrol 根据某一列数据来控制其他列合并

    首先需要属性栏中设置这一列可以合并,再在CellMerge方法中写 private void gridView1_CellMerge(object sender, DevExpress.XtraGri ...

  9. python中网络编程之线程

    网络编程之线程 什么是线程? 程序的执行线路.每个进程默认有一条线程.线程包含了程序的具体步骤. 多线程就是一个进程中有除主线程(默认线程)外还有多个线程. 线程与进程的关系(进程包含线程,而线程依赖 ...

  10. 安装Python的numpy库

    1. 检查是否有pip.exe, 如果没有,可以到 https://pypi.org/project/pip/#files下载 2. 安装好pip后,在安装numpy之前,查看是否安装成功,pip - ...