首页 > 系统相关 >CF342E Xenia and Tree

CF342E Xenia and Tree

时间:2023-12-28 16:58:18浏览次数:35  
标签:fir cnt int void CF342E Tree Xenia array include

题意

给定一棵 \(n\) 个节点的一棵树,初始时 \(1\) 号点为红色,其余为蓝色。

要求支持以下操作:

  • 将一个节点变为红色。
  • 询问节点 \(u\) 到最近红色节点的距离

共 \(q\) 次操作。

Sol

喵喵题。

不难想到点分树做法,不再阐述。

考虑简单的操作分块。

  • 对于块外,可以考虑每做完一个块就暴力 \(dp\) 重构。这部分复杂度为 \(O(q \times \sqrt n)\)。
  • 对于块内,考虑暴力计算答案,用 \(O(n \log n) ~ O(1)\) lca即可。

简单提一下 \(O(n \log n) ~ O(1)\) lca。

考虑树的欧拉序列。

记 \(dfn_x\) 表示第一次访问节点 \(x\) 的时间、\(idx_{cnt}\) 表示时间为 \(cnt\) 访问的节点。

考虑两个点走过的路径,不难发现 \(min_{i = dfn_u} ^ {dfn_v} idx_i\) 即为 \(lca\) 的时间。

直接 \(st\) 表维护即可,可以使用 +1-1rmq 做到 \(O(n) ~ O(1)\)。

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <cmath>
using namespace std;
#ifdef ONLINE_JUDGE

#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;

#endif
int read() {
	int p = 0, flg = 1;
	char c = getchar();
	while (c < '0' || c > '9') {
		if (c == '-') flg = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		p = p * 10 + c - '0';
		c = getchar();
	}
	return p * flg;
}
void write(int x) {
	if (x < 0) {
		x = -x;
		putchar('-');
	}
	if (x > 9) {
		write(x / 10);
	}
	putchar(x % 10 + '0');
}
const int N = 1e5 + 5, M = 2e5 + 5, inf = 2e9;

namespace G {

array <int, N> fir;
array <int, M> nex, to;
int cnt;
void add(int x, int y) {
	cnt++;
	nex[cnt] = fir[x];
	to[cnt] = y;
	fir[x] = cnt;
}

}

namespace Esl {

array <int, M> dfn, idx;
array <int, N> fa, dep;
int cnt;

void dfs(int x) {
	cnt++;
	dfn[x] = cnt;
	idx[cnt] = x;
	for (int i = G::fir[x]; i; i = G::nex[i]) {
		if (G::to[i] == fa[x]) continue;
		dep[G::to[i]] = dep[x] + 1;
		fa[G::to[i]] = x;
		dfs(G::to[i]), cnt++, idx[cnt] = x;
	}
}

array <array <int, 22>, M> sT;
array <int, M> lg;

void init() {
	for (int i = 1; i <= cnt; i++)
		lg[i] = log2(i);
	for (int i = 1; i <= cnt; i++)
		sT[i].fill(inf);
	for (int i = 1; i <= cnt; i++)
		sT[i][0] = dfn[idx[i]];
	for (int j = 1; j < 21; j++)
		for (int i = 1; i + (1 << j) - 1 <= cnt; i++)
			sT[i][j] = min(sT[i][j - 1], sT[i + (1 << (j - 1))][j - 1]);
}

int query(int _l, int _r) {
	int l = min(dfn[_l], dfn[_r]), r = max(dfn[_l], dfn[_r]), len = lg[r - l + 1];
	return idx[min(sT[l][len], sT[r - (1 << len) + 1][len])];
}

}

array <int, N> f;

void dfs1(int x) {
	for (int i = G::fir[x]; i; i = G::nex[i]) {
		if (G::to[i] == Esl::fa[x]) continue;
		dfs1(G::to[i]);
		f[x] = min(f[G::to[i]] + 1, f[x]);
	}
}

void dfs2(int x) {
	for (int i = G::fir[x]; i; i = G::nex[i]) {
		if (G::to[i] == Esl::fa[x]) continue;
		f[G::to[i]] = min(f[x] + 1, f[G::to[i]]);
		dfs2(G::to[i]);
	}
}

const int blk = 352;

void remake() { dfs1(1), dfs2(1); }

int calc(int x) {
	return (x - 1) / blk + 1;
}

array <int, N> arc;

int main() {
	int n = read(), m = read();
	for (int i = 2; i <= n; i++) {
		int x = read(), y = read();
		G::add(x, y), G::add(y, x);
	}
	f.fill(inf), f[1] = 0;
	Esl::dfs(1);
	/* puts("@"); */
	Esl::init();
	/* puts("#"); */
	remake();
	for (int i = 1; i <= m; i++) {
		int op = read(), x = read();
		arc[i] = 1;
		if (op == 1) {
			f[x] = 0;
			arc[i] = x;
		}
		else {
			int ans = f[x];
			for (int j = (calc(i) - 1) * blk + 1; j < i; j++)
				ans = min(ans, Esl::dep[x] + Esl::dep[arc[j]] - 2 * Esl::dep[Esl::query(x, arc[j])]);
			write(ans), puts("");
		}
		if (i % blk == 0) remake();
	}
	return 0;
}

标签:fir,cnt,int,void,CF342E,Tree,Xenia,array,include
From: https://www.cnblogs.com/cxqghzj/p/17933065.html

相关文章

  • layui 树组件tree 通过API获取数据
    一、简单vartreedata=[]; tree.render({ elem:'#addLeftType', id:'demoId', data:treedata, showCheckbox:true, oncheck:function(obj){ console.log(obj.data);//得到当前点击的节点数据 console.log(obj.checked);//节点是否被选中 console.l......
  • 【CF1917F】Construct Tree
    题目题目链接:https://codeforces.com/contest/1917/problem/F给出\(n\)条边的边权,询问是否可以构造出一棵树,使得所有边都被用上恰好一次且直径为\(d\)。\(n,d\leq2000\)。思路首先肯定是找出一条长度为\(d\)的链,然后判断可不可以把剩下的所有边都挂在这条链的带权重心......
  • CF396C On Changing Tree 题解
    CF396C考虑将贡献表示出来:\(\forallv\in\text{subtree}_u\),\(v\)会加上\(x-(dep_v-dep_u)k\),然后发现这个东西可以维护整棵子树,即把\(x,dep_u\timesk\)和\(dep_v\timesk\)分开计算,然后\(dep_v\)可以最后再管,就变为子树加,单点和了。用树状数组维护dfs序即可。......
  • C++ Qt开发:TableView与TreeView组件联动
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍TableView与TreeView组件联动的常用方法及灵活运用。本章我们继续实现表格的联动效果,当读者点击T......
  • 【OpenCV】【Python】关于cv2.findContours()轮廓索引(编号)解析(RETR_TREE)
    在打算自己实现二维码的定位的时候,看到了相关博文的关于cv2.findContours返回的层级信息来定位三个“回”字从而达到定位二维码的目的,但是返回的hierarchy中的层级信息分别对应的是哪个轮廓却困扰了许久,查阅了很多资料最后还是自己手动找出了清晰的规律。关于hierarchy返......
  • CodeForces 1917F Construct Tree
    洛谷传送门CF传送门考虑形式化地描述这个问题。先把\(l\)排序。然后相当于是否存在一个\(\{1,2,\ldots,n\}\)的子集\(S\),使得:\(\sum\limits_{i\inS}l_i=d\)。\(\existsT\subseteqS,\max\limits_{i\notinS}l_i\le\min(\sum\limits_{i\inT}l_i,\sum......
  • .net自带的树控件TreeView用法
    原文链接:https://blog.csdn.net/wenchm/article/details/133276828https://blog.csdn.net/xiaogongzhu001/article/details/131100371    TreeView控件(树控件)可以为用户显示节点层次结构,每个节点又可以包含子节点,包含子节点的节点叫父节点。就像在Windows操作系统的Wind......
  • C# WinForm控件之advTree
    原文链接:https://www.cnblogs.com/SoftWareIe/p/8757270.html0.属性和方法//属性方法advTree1.DragDropEnabled=!advTree1.DragDropEnabled;//控制是否可以拖动节点advTree1.MultiSelect=!advTree1.MultiSelect;//控制节点是否可以多选advTree1.ExpandButtonType=Dev......
  • 一个功能更强大,性能更高的树控件DevComponents.AdvTree.AdvTree(几种树形控件汇总)
    原文链接:https://www.cnblogs.com/a7373773/archive/2009/07/27/1532236.html一直在用DevComponents.DotNetBar2 控件近来探索Add()和AddRange()的性能问题。一样用极为不专业不科学的方法,比较DevComponents.AdvTree.AdvTree的Add()和AddRange()的性能 1private void butt......
  • Codeforces1917F - Construct Tree
    Codeforces1917F-ConstructTreeProblems给一个长度为\(n\)的序列\(l\)和\(d\)。要求判断是否可以构造出一颗节点数为\(n+1\)的树,满足\(l\)的每一个元素唯一对应为一条边的长度,并使整棵树的直径长度恰好为\(d\)。Solution不妨令\(l_1\lel_2\le\cdots\lel_......