首页 > 其他分享 >杂项乱写 9.29

杂项乱写 9.29

时间:2024-09-29 11:44:33浏览次数:1  
标签:sort 乱写 9.29 len int lt dfn dfs 杂项

因为没有模拟赛,所以考虑捡捡之前漏下的小点。

注:LCA 之后的讲解中可能会出现一些自由的文字,酌情阅读。


dfs 序求 LCA

倍增 LCA 的常数还是过于大了,虽然好记但会导致我们在一些数据奇异的题中比其它方式求 LCA 的人的得分要低。

所以就有了这个用 dfs 序求 lca 的高科技,在时间效率和代码好写程度上都薄纱其它方法的狠活。

思路

建议画个简单图手模一下

设我们要求 \(u\),\(v\) 两点的 lca 为 \(d\),两点不重合,令 \(dfn_u\lt dfn_v\)。

首先考虑 \(u\),\(v\) 之间不存在祖先关系的情况。此时 dfs 的顺序是从 \(d\) 到 \(u\) 再回退到 \(d\) 再到 \(v\)。那么根据 dfs 的性质,任何 \(d\) 及其祖先的点均不会出现在 \(dfn_u\) 到 \(dfn_v\) 这个范围内;再考虑 \(d\) 在 \(v\) 方向的第一个子节点 \(x\),显然有 \(dfn_u\lt dfn_x\lt dfn_v\)。也就是说,我们只需要找出一个 dfs 序在上述范围内的深度最浅的点,其父节点就是我们所求的 \(d\)。

再考虑二者存在祖先关系怎么处理。暴力判断虽然可行,但与我们这样做的目的就相悖了,我们要找到一个优雅的方式来求解。由 \(dfn_u\lt dfn_v\) 可知 \(u\) 为 \(v\) 祖先,我们按上述方法寻找到的 \(x\) 为 \(u\),显然与答案不符。所以我们考虑修改上述范围,将其改成 \(dfn_u+1\) ~\(dfn_v\) 即可。思考这样做在情况一的正确性,由于 \(u\) 显然不能成为我们要找的 \(x\),所以去掉该点不会对答案造成影响。

唯一的不足就是无法处理 \(u=v\) 的情况,特判一下即可。

实现

借助 ST 表来完成,预处理的复杂度是 \(\mathcal{O(n\log n)}\) 的,但常数小了很多。

模板题代码:

const int Ratio = 0;
const int N = 5e5 + 5;
int n, m, s;
namespace WLCA
{
	int dfn[N], tot, st[31][N], lg[N];
	int hh[N], to[N << 1], ne[N << 1], cnt;
	void Wadd(int u, int v){to[++cnt] = v, ne[cnt] = hh[u], hh[u] = cnt;}
	int Wget(int x, int y){return dfn[x] < dfn[y] ? x : y;}
	void Wdfs(int u, int fa)
	{
		dfn[u] = ++tot, st[0][dfn[u]] = fa;
		for(int i = hh[u]; i != -1; i = ne[i])
		{
			int v = to[i];
			if(v == fa) continue;
			Wdfs(v, u);
		}
	}
	int Wlca(int x, int y)
	{
		if(x == y) return x;
		if((x = dfn[x]) > (y = dfn[y])) swap(x, y);
		int d = lg[y - x++];
		return Wget(st[d][x], st[d][y - (1 << d) + 1]);
	}
	short main()
	{
		n = qr, m = qr, s = qr;
		memset(hh, -1, sizeof hh);
		for(int i = 1; i < n; i++)
		{
			int a = qr, b = qr;
			Wadd(a, b), Wadd(b, a);
		}
		Wdfs(s, 0);
		for(int i = 2; i <= tot + 1; i++)
			lg[i] = lg[i >> 1] + 1;
		for(int i = 1; i <= lg[n]; i++)
			for(int j = 1; j + (1 << i) - 1 <= n; j++)
				st[i][j] = Wget(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);
		for(int i = 1; i <= m; i++)
		{
			int a = qr, b = qr;
			printf("%d\n", Wlca(a, b));
		}
		return Ratio;
	}
}
  • 顶针教的,讲的比较好的是这篇博客,引用了部分内容。

建虚树

众所周知,点有五个,关键点有三个。

你说的不对,但是虚树有两种建法,一种是好写好理解复杂度不好的双 sort 建树,一种是不好写不好理解复杂度好的单调栈维护。但是题解不会顺着你的思路来,所以两种方法都要深度理解下。

双 sort 建树

思路

好理解,不写了。

其实理解它主要依赖于理解虚树到底要留哪些点。知道为什么留 lca 了就明白为什么这么建树了。

实现很简单,按 dfs 序 sort 一遍,开随便什么存一下每个点及相邻点的 lca,再 sort 一遍,再 unique 一遍,然后根据原树上关系加边就行了。

实现

好写,不写了。

int dfn[N], tot, a[N], b[N], m, len;
bool cmp(int a, int b){return dfn[a] < dfn[b];}
void Wbuild()
{
	sort(a + 1, a + m + 1, cmp);
	for(int i = 1; i < m; i++)
		b[++len] = a[i], b[++len] = Wlca(a[i], a[i + 1]);
	b[++len] = a[m];
	sort(b + 1, b + len + 1, cmp);
	len = unique(b + 1, b + len + 1) - b - 1;
	for(int i = 1; i < len; i++)
	{
		int lca = Wlca(b[i], b[i + 1]);
		Wadd(lca, b[i + 1]);
	}
}

单调栈建树

5k:为什么要学单调栈建树?

Ratio:不是说这个跑得快点

5k:复杂度都是一样的,少的这点常数也不会去卡,再说了单调栈你还容易写挂,双 sort 就很难写挂

所以不写这个了。

差分约束

由于昨天晚上饭堂,导致写 D 时被迫复习了差分约束。

经过

具体的,开始先打了一遍本来能过的 dfs 做法,然后由于我觉得可能会爆 1e18 就很天才的给 i 赋了一个 \(\frac{max+min}{2}\),然后其它还有很多脑瘫的地方所以 WA + TLE 导致我觉得这种做法不可行然后怒吃 8 发罚时。

差分约束系统 是一种特殊的 \(n\) 元一次方程组,它包含……

嗯,这有啥好说的,还是挑重点吧。

给你若干个形如 \(x_i + x_j \le k\) 的限制,询问是否有符合上述所有限制的解。

思路

联想大法好:发现 \(x_i - x_j \le k\) 和求醉短路中的松弛操作 \(dis_v\lt dis_u +w_i\) 很像,因此我们将每一个数 \(x_i\) 都当做图中的一个点,每个约束看作由 \(x_j\) 向 \(x_i\) 引一条长度为 \(k\) 的边。

如果符号是 \(\gt\) 你就两边同时乘上一个 \(-1\),如果是 \(=\) 你就看成两个限制 \(x_i-x_j\le k\),\(x_j-x_i\le -k\),连两条边就行了。至于其它的符号,本质上没啥区别,自己转化一下。

实现

公元 4202 年,智慧的人类掌握了复活已死的事物这一技术,并以 SPFA 为对象进行了秘密测试,结果未知。

采用 SPFA 算法,若跑出负环了显然是无解的情况,否则跑出的 \(dis_i\) 就是所有限制下的一组解。

由于限制是以差分形式存在的,所以若 \(a_1,a_2\cdots a_n\) 是符合题目要求的一组解,那么 \(a_1 + k,a_2+k\cdots a_n+k\) 也是符合要求的另一组解。由这个性质可以实现一些题目中对解的范围限制。

例题:无

啊不对,昨天晚上刚做了一道。

例题:有

Problem

谔谔虽然你们暴力都过了并且我的暴力改完也过了,但我赛时打的差分约束所以它就是模板题。

很好的条件,确保了一定有解,所以我们完全可以省掉判负环的步骤,直接开局建一个超级原点,按差分的性质连边,跑一遍就没了,因为 \(10^9\times 2\times 10^5\lt 10^{18}\),所以压根不用管题目的 \(x_i\le |10^{18}|\),初始值设成 0 肯定跑不炸。

Submitted code 这里放的现打的因为赛时太唐了做了一堆唐氏操作,喜欢唐人的可以自己去搜。

鲜花

  • 1 能不能不要再逆天发言了,哦好像这几个字排列已经被你们发掘完了,怪不得没动静了

  • 2
    Ratio:jijidawang 你想说点什么吗
    jijidawang:我想说点什么吗


完结撒花~

image

标签:sort,乱写,9.29,len,int,lt,dfn,dfs,杂项
From: https://www.cnblogs.com/Ratio-Yinyue1007/p/18439106

相关文章

  • 2024.9.29 计划
    项目学习ROS第三章背包问题求具体方案能量石金明的预算方案(有依赖的背包问题)总结......
  • 9.23 ~ 9.29
    9.23集训第一天。早晨因为太多人没拿早读资料被老登D了。不是哥们你不早说现在我上哪给你找资料去......
  • 9.22~9.29
    9.22刚回到学校,还没有摆脱浮躁之气,决心先做一个调整,把准方向首先,文化课学习要进行大调,主攻数学,英语常客,语文辅助数学规定每天一小时,前25分钟学习1~3小章不等,后25分钟专注刷本章书后习题然后周六周日规定每晚8~9点对本周数学情况进行整理,并专项练习语文每天晨间早饭诵读一遍,10......
  • 『杂项』Linux 常用指令
      不会吧不会吧不会还有Oier不会Linux指令要写一篇博客记一下  今年S组人数骤增,遂ctrl+cv出本篇博客以获得两分(Linux常用指令文件和目录管理命令ls:列出当前目录中的文件和子目录。pwd:显示当前工作目录的路径。cd:切换工作目录。mkdir:创建新目录。rmdi......
  • 杂项——矩阵加速(进阶)
    前言:在之前已经学习过矩阵快速幂的用法,那些只是基础。在ICPC中大多数难度较高,且并不是简单的只需要常数的矩阵或者简单的图上问题,而是结合dp方程去推导出来转移矩阵。trick:例题:链接:https://ac.nowcoder.com/acm/contest/88880/E来源:牛客网给出两个整数\(n,k\),有一个正整数......
  • CTF学习-MISC杂项解题思路
    文件操作与隐写文件类型识别 1.File命令当文件没有后缀名或者有后缀名而无法正常打开时,根据识别出的文件类型来修改后缀名即可正常打开文件。使用场景:不知道后缀名,无法打开文件。格式:filemyheart2.winhex通过winhex.程序中可以查看文件头类型,根据文件头类型判断出......
  • C++ 使用终端GDB调试复杂项目中Segmentation Fault 和 std::bad_alloc问题
            近期在公司虚拟机上写代码遇到SegmentationFault和std::bad_alloc问题,但是项目庞大,在不了解功能、代码连接关系的时候很难追踪具体是什么地方出了问题。网络上许多关于GDB的教程仅仅停留在简单的示例中的调试,对于复杂的项目结构(多文件,多作用域,......)来说显......
  • C++基础之杂项
    目录思维导图:学习内容:1. Lambda表达式1.1基本概念1.2定义格式1.3常用情况二、异常处理2.1什么是异常处理2.2何时使用异常处理2.3异常处理的格式2.4异常实例2.5构造和析构中的异常 2.6系统提供异常类 三、C++中文件操作3.1文件流对象的介绍3.2关......
  • Cortex-M3的杂项知识
    必备知识stm32的框图Cortex-M微控制器复位流程向量表中向量地址的最低为应该为1,这里指的是向量表中存储的地址如何查看反汇编代码汇编语言:汇编语言是一种低级语言,是针对某种机器而言的。应用程序的状态应用程序具有静止状态和运行状态。静止态的程序被存储在非易......
  • 【CTF杂项】常见文件文件头、文件尾格式总结及各类文件头
    原创小羽网安1、从Ultra-edit-32中提取出来的附件:文件格式分析器JPEG(jpg),文件头:FFD8FFPNG(png),文件头:89504E47GIF(gif),文件头:47494638TIFF(tif),文件头:49492A00WindowsBitmap(bmp),文件头:424DCAD(dwg),文件头:41433130AdobePhotoshop(psd),文件头:38425053RichT......