自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(211)
  • 收藏
  • 关注

原创 平面最近点对

【代码】平面最近点对。

2023-10-11 18:49:20 61

原创 红黑树原理与代码

红黑树笔记

2023-02-06 14:29:43 305

原创 左式堆代码

struct node{ int val; int len; // 最短路径长度 node *lc,*rc; node(int a,int b,int c) { val = a; siz = b; len = c; lc = NULL; rc = NULL; }};void update(node *a) { // 更新当前节点信息 node *l = a->lc; node *r = a->rc; int len1 = 0; int len2

2022-05-26 10:36:49 130

原创 双向bfs

双向搜索适用于起点和终点状态都很明确的搜索题。对于正常的bfs,就像从一个圆从中心向外发散,开销的话就是面积。但是我们可以从起点和终点一起开始搜索,相遇到一个点的时候搜索就结束了,这样的复杂度就是两个小圆的面积。#include <iostream>#include <queue>#define P pair<int, int>using namespace std;//记录下当前状态, 从前往后搜索值为1,从后往前搜索值为2,如果某状态下,当前节点和准备扩展节

2022-02-24 17:16:19 317

原创 AcWing 3256. 商路(dfs序+线段树+斜率优化)

题目  首先可以比较容易的写出dp的转移,化简后发现是含有i和j的乘积形式,所以可以想到斜率优化。化简后可以发现决策点就是(2*dis[j], dp[j]-dis[j]*dis[j]),斜率是-(f[i]+dis[i])。  但是决策的范围是在i的子树,并不是传统的[1,i-1]。所以使用dfs序将子树问题转化为区间问题。注意斜率优化的决策点的横坐标需要单调递增,所以每个线段树节点需要维护当前区间的节点,并按横坐标排序,用这些决策点维护一个斜率单调递减的序列。但是横坐标还可能相同,根据贪心,如果横坐标相

2021-08-04 12:51:14 181

原创 线段树分裂与合并

对于动态开点的线段树来说,当有很多棵线段树时,我们可以进行线段树合并,合并两棵线段树的复杂度为两棵线段树相同节点的数m*logm。将y这棵线段树合并到x这棵线段树,对于x没有y有的节点,直接复制y的就行,x有y没有的不用管,都有的加起来即可。void insert(int &now,int l,int r,int p,int v) //动态开点,将p位置的值加v{ if( now == 0 ) now = ++cnt; if( l == r ) { a[now].maxt +=

2021-03-28 22:18:49 457

原创 根号分治

当我们会碰到这样一类问题时,长度为n的序列,m个询问(通常n和m同阶)。可能存在两种比较显然的方法,一种是O(n^2)预处理O(1)回答,一种是不预处理O(n)回答m个询问,当然这两种方法都是O(n2)的。这时候我们就可以考虑根号分治,将这两种算法糅合在一起,达到一个nsqrt(n)的效果。题目:给定n个集合,输出是否存在两个集合,他们至少有两种元素相同,集合总数不超过2e5。分析:对于这个题目,可以想到两种暴力的方法。1.对于每个集合,暴力查找别的集合是否与其匹配。2.预处理出所有的二元对,查看他

2021-03-17 20:48:29 1069 2

原创 D. BFS Trees(bfs+枚举计数)

题目题意:    给定一张n个点m条边的联通无权图,要求输出对于任意的i,j,在原图中有多少棵生成树,使得i,j到生成树上的任意一点的距离等于i,j在原图上到达他们的距离。    1≤n≤400,1≤m≤6001≤n≤400,1≤m≤6001≤n≤400,1≤m≤600分析:    首先我们预处理出所有点的最短路。然后我们考虑将一个点x加入到最小生成树,那连那条边呢?能连的点的距离一定是x与i的距离减一,x与j的距离减一,这样连上去才能保证i,j到x的距离为最短距离。    还有一种点,他们在i

2021-03-15 12:17:10 165

原创 C. Break Up(枚举+割边)

题目题意:    给定一张n个点m条边的带权图,输出是否可以删去最多两条边,使得s与t不连通。有多种方案时输出权值最小的方案,没有则输出-1。    1≤n≤1e3,1≤m≤1e41≤n≤1e3,1≤m≤1e41≤n≤1e3,1≤m≤1e4分析:    可以注意到n比较小,而且最多删两条,那就考虑能否枚举一条,再去尝试删去另一条。那我们枚举的这一条边一定是在s到t的一条路径上的,且这条路径上一定要删去一条边。所以我们先找到s到t的一条路径,枚举删去这条路径上的一条边,现在的问题就变成删去一条边,能

2021-03-11 18:26:22 116

原创 E. Ehab‘s REAL Number Theory Problem(思维+最小环)

题目题意:    给定一个序列,这个序列的因子数不超过7个,要求从这个序列里拿出尽可能少的数,使得他们的乘积为完全平方数。无解输出-1。    1≤n≤1e5,1≤a[i]≤1e61≤n≤1e5,1≤a[i]≤1e61≤n≤1e5,1≤a[i]≤1e6分析:    首先完全平方数有一个性质,就是素因子分解后,每个素因子的指数都是偶数,所以对于一个数它的素因子是偶数的就不用考虑了。其次我们考虑每个数字的因子数不超过7个,那么可以发现素因子个数不超过2个。那么选择一个数就变成了选择两个素因子(只有一个

2021-03-10 18:07:32 163

原创 D. Graph and Queries(可撤销并查集+启发式合并+set维护)

题目题意:    给定一张无向图,n个点,m条边。每个点都有点权,点权互不相同,有两种操作。    操作1:1 v,输出v点所在的连通块的点权最大值,并将那个点的权值置为0。    操作2:2 i,将第i条边删去。    1≤n≤2e5,1≤m≤3e5,1≤q≤5e5。1≤n≤2e5,1≤m≤3e5,1≤q≤5e5。1≤n≤2e5,1≤m≤3e5,1≤q≤5e5。分析:    这种带有删边的题目一般都会考虑从后往前加边,但是这道题每次输出答案的时候同时修改了点权,所以从后往前似乎无法操作。再考

2021-03-09 22:49:36 162

原创 C. Greedy Shopping(线段树+复杂度分析)

题目题意:    有n个商店,每个商店吃一顿饭需要a[i]元,保证a[i]单调不减。现在有q次操作:    操作1:1 x y,表示将区间[1,x]的a[i]变为max(a[i],y);    操作2:2 x y,现在有一个人有y元钱,从x个商店开始,如果能吃饭,就花费a[i]元钱吃一顿,否则就不吃去下一家,一直到第n家,输出一共能吃多少顿。    1≤n≤2e5,1≤q≤2e5。1≤n≤2e5,1≤q≤2e5。1≤n≤2e5,1≤q≤2e5。分析:    首先这个是对区间进行操作,我们可以很

2021-03-09 22:40:41 127

原创 关于约数的题目

约数个数定理设n=∏i=1kpiqi设 n=\prod^k_{i=1}p_{i}^{q_{i}}设n=∏i=1k​piqi​​则n的约数个数为∏i=1k(qi+1)。则n的约数个数为\prod_{i=1}^{k}(q_i+1)。则n的约数个数为∏i=1k​(qi​+1)。

2021-03-09 17:47:47 295

原创 线段树优化建图

给定n个点,有三种操作:1.连一条从x到y权值为w的边。2.连一条从[l,r]到y权值为w的边。3.连一条y到[l,r]权值为w的边。给定一个起点,求单源最短路。/*线段树优化建图对于点到区间上所有点都加上一条路径这样的操作可以考虑线段树来优化建图将区间考虑成点,那么点到区间的边就变成为点到一些点的边(这些点不会超过log次)线段树的叶子节点就是真实的点线段树每个节点又需要拆为两个点,一个点可以到达它的所有儿子,一个点可以被它的所有儿子到达从这个区间出去一条路径(这个是从其儿子节点跑

2021-03-05 20:42:11 190

原创 prufer序列

/*prufer序列prufer序列其实就是将带有标号的n个节点(即每个节点不等价)的树用[1,n]的n-2个数唯一表示即n个点的完全图的生成树与长度为n-2的prufer序列构成一一对应的关系 所以根据prufer序列,我们可以知道,完全图生成树的个数为n^(n-2) */#include <iostream>using namespace std;typedef long long ll;const int maxn = 5e6+5;int f[maxn],p[max

2021-03-04 19:48:37 160 1

原创 笛卡尔树

笛卡尔树上的每个点都是一个二元对(x,y),树对于x来说是一棵二叉搜索树,对于y来说是一个堆。对于x序已经单调的一个序列,可以O(n)建出笛卡尔树。顺序遍历对于新加进来的点i,找到第一个y小于等于它的点v(这里是小根堆),那么v的右子树就是i了,如果v有右子树,那么这个右子树作为i的左子树。如果没有这个点,那么i就是根了。int a[maxn],sta[maxn],l[maxn],r[maxn];int top = 0;int build(int n) //返回笛卡尔树的根{ int

2021-03-04 12:38:52 292 1

原创 无旋treap(fhq treap)

普通平衡树/*无旋treap(fhq treap)treap是二叉搜索树结合二叉堆来的,它保证树上任意节点,右节点值一定大于当前节点,儿子节点的索引一定小于父亲节点 对于任意一个点随机赋索引,这样的树就保证了随机,从而不会被卡链无旋treap主要引入了分裂和合并两个操作,从而可用来处理很多问题 */#include <iostream>#include <cstdlib>#include <ctime>using namespace std;c

2021-02-26 21:52:22 327

原创 梅森素数

梅森数位形如2^p-1这样的数字,当这个数是素数时,称为梅森素数。目前找到的梅森素数有51个。a数组里存放的是p,而非真正的梅森素数。ll a[]={0,2,3,5,7,13,17,19,31,61,89,107,127,521,607,1279,2203,2281,3217,4253,4423,9689,9941,11213,19937,21701,23209,44497,86243,110503,132049,216091,756839,859433,1257787,1398269,2976

2021-02-24 16:58:08 1330

原创 克鲁斯卡尔重构树

克鲁斯卡尔重构树就是在用克鲁斯卡尔算法计算最小生成树时,构造出一棵树。当题目需要用到最小生成树时,常常利用重构树将其转化为树上问题。重构过程:在连接两个点时,将其连向一个新点,新点的点权为这条边的边权。并查集上就把这两点的父亲设为这个新点。这样我们就维护了一棵从底向上点权递增的一棵二叉树。这棵树具有很多的性质,以解决不一样的问题。1.对于两个点,他们之间最小路径的最大值就在他们的lca上。2.通过倍增,我们可以求得一个点y在经过的权值不超过z能到达的所有点。倍增到那个点,那个点为根的子树就都是可达

2021-01-27 20:35:24 1131

原创 圆方树

圆方树是用于处理无向图上的一类问题,将图的点双连通分量作为一个方点,将这张图变为一棵树,一般观察到题目的要求中点双上具有一些性质时常常可以考虑使用圆方树将图转化为树。在圆方树中,原来的每个点对应一个圆点,每一个点双对应一个方点。所以共有n+c个点,其中n是原图点数,c是原图点双连通分量的个数。而对于每一个点双连通分量,它对应的方点向这个点双连通分量中的每个点连边。每个点双形成一个“菊花图”,多个“菊花图”通过原图中的割点连接在一起(因为点双的分隔点是割点)。圆方树的性质:1.树上只存在“圆圆边”和“圆

2021-01-27 11:27:58 355

原创 图的绝对中心与最小直径生成树

图的绝对中心在图中找到一个点,使得它到所有其他点的最短路径的最大值尽可能小。首先绝对中心到最远的两个点的距离一定是相等的。我们直接枚举每条边(u,v),考虑这个绝对中心在距离u为x的位置。这时我们考虑这条边以外的任意一个点w,那么可能的答案为min(dis[u][w]+x,dis[v][w]+g[u][v]-x),我们将其画图,x为横坐标,答案为纵坐标,会发现图像是一条折线。我们多尝试画一些点,会得到一些折线,看图像可以发现最优值只会在折线的最低点取到,而且这些最低点只会出现在交点处。观察会发现dis

2021-01-24 12:00:37 276

原创 最长k可重区间集问题

给定n个区间,要求对于数轴上的每个点,不能被超过k个区间覆盖。要求满足条件下选出的区间长度和尽可能大。分析:首先,如果这些区间的端点覆盖都小于k次,那么其他点被覆盖肯定小于k次,所以我们只需要离散化一下,考虑这些端点即可。我们考虑假设k为1,那么如果选择了某一区间的l端点,那么可以直接到这个区间的r,在[l,r]这一区间内的所有点都不能被选了。所以我们对于每个左端点,都连一条流量为1的边(因为只能选一次),费用为长度的边(因为要求最大长度,所以需要费用流)。因为左端点可能不选,所以我们需要将这个端点向

2021-01-21 10:27:26 261

原创 线段树分治

线段树分治是一种离线做法,处理的是某种修改对询问的影响,这种影响可以独立也可以不独立。关键是把一个修改看成一个区间,每个询问是一个叶子。修改是在线段树上打标记。这里把询问看做一个时间点,而修改对应一个时间区间的修改。做法:在线段树上记录要操作的时间区间,dfs依次执行这一操作,一直到根节点来回答询问,离开时将其撤销。题目: 有两种操作,一种是将两个点连一条边,另一种就是询问这个点所在的连通块的点数,但是这个边的有效时间只有k天。每次操作过一天。分析: 如果没有有效时间的话,就是并查集的裸题。那么一次

2021-01-20 22:51:23 1067

原创 可撤销并查集

可撤销并查集是支持后悔操作的并查集,注意这时写并查集一定要按秩合并,路径压缩会改变节点与节点之间的关系,改了这个关系那就没法回退了。思路:用一个栈维护每次操作更新的节点,回退时找到那两个回退即可。注意一定是后操作的先反悔。int parent[maxn],siz[maxn]; //按秩合并用siz,siz小的连向siz大的 vector<pii> tmp; //记录上次合并用到的节点 int find(int p) //递归找根节点,注意没有路径压缩 { if(

2021-01-20 22:41:33 3194

原创 树上背包问题

树上背包问题主要是处理当前节点要从其儿子节点转移过来,但是儿子节点的第二维度是变化的,需要取出其中一个值与其他儿子的值拼凑出一个想要的值。所以就有背包的意味在里面了。洛谷P3177给定一棵n个节点的树,要求将k个点染成黑色,其余的点为白色。贡献为任意两个颜色相同的点的距离。求一个染色方案使得贡献尽可能的大。分析:计算贡献一般就是考虑每条边对答案的贡献,那么dp[i][j]就可以表示以i为根的子树,其中已经染了j个节点为黑色的最大贡献。这样对于转移我们就只需要加上这条的贡献了。但是对于儿子的枚举,看起

2021-01-07 15:06:43 948

原创 带有上下界的网络流

无源汇带上下界的可行流n个点,m条边,每条边有一个流量下界和流量上界,求一种可行方案使得在所有点满足流量平衡条件的前提下,所有边满足流量限制。分析:首先假设每条边的流过的流量为其下界,如果能流量平衡,那么就存在可行解。但是存在着流量不平衡的情况,所以我们需要调整每个边的流量,使得流量平衡。那么每条边可以调整的流量即为上界减去下界,意义就在于若这条边有流量,则最后的可行流会多出这些流量,这样保证最后的可行流不会超出上界。然后对于每个点我们维护其下界情况下的in与out流量。若一个点in[i]>

2020-12-17 22:24:05 286

原创 网络流训练总结

1.表达图中点的互斥关系当我们在解题时,需要取某些点,但是取完这些点后,有些点就不能取了,即点与点之间存在互斥关系。但是网络流中连边似乎只有关联的关系,没有这种互斥关系。其实我们可以让互斥的点连边,流量为无穷大。我们尝试用最小割分割他们,最小割后,图不再连通,那么这条边永远不会被走到,即永远不会发生冲突。洛谷2774给定一个n*m的矩阵,每个点都有权值,取了一个点后就不能取周围的点了,求出能取到的最大值。分析后可知,坐标和为奇数的与偶数的互斥,所以构成了一张二分图。对于二分图的互斥,我们对互斥的点

2020-12-10 20:20:26 238

原创 动态dp

/*动态dp,支持修改操作的dp最大值最小值维护定义广义矩阵乘法c[i][j]=max(a[i][k]+b[k][j]) 加法对min与max有结合律 对于转移g[i]=max(g[i-1],f[i]),f[i]=max(f[i-1]+a[i],a[i])尝试构造矩阵,利用线段树来维护区间的广义矩阵乘法的值,这样就能算区间的dp值 */#include <iostream>#include <cstring>using namespace std;typed

2020-11-24 17:45:40 279

原创 斯坦那树

/*斯坦那树:一个无向图,n个点m条边,有k个关键点,求联通这k个点的最小代价由于最后的结果一定是一棵树,所以dp[i][s]表示以i为根,当前连通状态为s的代价,注意每个点都可能为根. dp[i][s]可以由s的子状态转移过来,也可以由别的点j通过i,j这条边与i相连形成以i为根的s即dp[i][s]=min(dp[i][j]+dp[i][s^j]) j为s的子集dp[i][s]=min(dp[i][s],dp[j][s]+val[i][j]) 那么这个式子本质上就是最短路了,对于每次的s,

2020-11-16 16:10:23 130

原创 斜率优化DP

/*斜率优化主要解决的是转移方程中存在一个同时与i和j有关的部分时的优化问题 dp[i] = min(dp[j]+a[i]*b[j]) 0<j<i;转移方程写为dp[j]=-a[i]*b[j]+dp[i]那么决策就变为了二维坐标的点集,最小化dp[i]就转化为了线性规划问题对于线性规划问题,考虑任意三个决策点,根据方程的不同来判断斜率应该如何单调而决策点就在a[i]的临界处,即某个顶点左侧线段的斜率和右侧线段的斜率与a[i]大小关系不同。当a[i]单调时,我们就可以利用单调队列来维

2020-11-15 21:24:36 191

原创 无向图的双连通分量

边双连通分量/*无向图的边双连通分量(e-DCC)及缩点 若一张无向图不存在桥,则称这张图为边双连通图极大边双连通图称为边双连通分量求法:用链式前向星存图方便标记边 找出原图中所有的桥,将桥去掉后形成的各个连通块即为边双连通分量 最后缩点就把双连通分量缩为一个点即可 */#include <iostream>#include <cstring>using namespace std;const int maxn = 5e4 + 5;struct e

2020-11-06 17:50:51 165

原创 虚树

/*虚树,是对于一棵给定的树,构造一棵新的树使得总结点数最小且包含指定的某几个节点和他们的LCA。虚树常常用于处理树上的给定点的问题,常常多组访问,总访问点数在1e5内 先预处理整棵树lca和dfs序,接下来是对于每组询问的构造。虚树的构建是一个增量算法,要首先将指定的这k个点按照dfs序排序,然后按照顺序一一加入,强行先加入根节点以方便后面的处理。后面流程看代码 */ #include <iostream>#include <vector>#include

2020-10-10 17:25:55 204 1

原创 bitset的用法

bitset,是一个仅含0/1的一个数组。但是它的每个位置只占1bit。主要用于快速的集合位运算。#include <iostream>#include <bitset> //使用时需要声明using namespace std;int main(){ ios::sync_with_stdio(false); cin.tie(0); //bitset<N> s N为数组的大小 bitset<23> s1(4); bitset

2020-10-07 16:23:41 271

原创 SOS dp

/*sosdp:枚举子集合进行的一些操作也称高维前缀和 复杂度:O(n*2^n)计算对于任意的i,f[i] = sum(a[j]),j为i的子集合 dp[i][j]表示对于i来说,仅考虑前j位可能不同的子集合.如果i的第j位为1,那么dp[i][j]=dp[i][j-1]+dp[i^(1<<j)][j-1]即子集合中,第j位为1和第j位为0的前j-1位相加否则dp[i][j]=dp[i][j-1],即第j位一定只能为0 */ #include <iostream&gt

2020-10-04 22:44:48 125

原创 G. Columns Swaps

题目题意:    给定2*n的数组,每次可以交换同一列的两个元素,要求使用尽可能少的操作使得每一维都形成一个n的排列。    1≤n≤2000001≤n≤2000001≤n≤200000分析:    要想满足条件,那么1-n的元素都要出现两次。考虑对于一个x,如果两个x在同一行,那么一定只能交换一列。如果在不同行,那么这两列要么不交换,要么都交换。对于这种双向边的操作,就可以用并查集来维护,而有向边则需要用2-sat。    所以我们使用一个并查集,i代表第i列需要操作,i+n代表第i列不需要操

2020-09-02 11:20:41 167

原创 dsu on tree(树上启发式合并)

/*树上启发式合并用于处理离线查询的子树问题第一次先求出重儿子第二次dfs的过程中,先计算轻儿子,贡献不保留,再计算重儿子,贡献保留最后再加上轻儿子的贡献,计算出当前节点的值 复杂度为O(nlogn) */ /*每个节点都有一个颜色编号 计算一棵以1为根的树的以每个节点为根的子树中颜色最多的颜色编号和这题中子树的贡献就在于cnt数组,用来计数颜色出现了多少次 */ #include <iostream>#include <vector>using n

2020-09-01 10:40:36 159

原创 树链剖分

树链剖分之重链剖分重儿子:一个节点的所有儿子中,大小最大的那个轻儿子:一个节点除了重儿子以外的所有的儿子重链:从一个轻儿子开始(包括根),一路往重儿子走,连出的链叫重链需要两次dfs第一次求重儿子等一系列的信息(结点的父亲,结点的重儿子,结点的深度,结点的大小)第二次dfs标记时间戳形成dfs序,第二次dfs优先往重儿子走,这样所有的重链的dfs序都是连续的(结点权值的dfs序,当前dfs序对应的权值,当前结点所在重链的头是谁,头的头是自己)复杂度:O(m*(logn)^2)/*利用df

2020-08-31 15:51:18 79

原创 可持久化并查集

/*可持久化并查集并查集的本质就是数组,所以可持久化并查集就是可持久化数组但是并查集的路径压缩不能用了,因为路径压缩会改变fa数组,在可持久化里,改变就意味着log的空间复杂度,所以不用路径压缩,改为秩优化,即将深度小的并到深度大的所以需要维护两个可持久化数组,开两倍空间 */ #include <iostream>using namespace std;const int maxn = 2e5 + 5;int rootfa[maxn],rootdep[maxn],cn

2020-08-29 10:04:00 1042

原创 可持久化数组

/*可持久化数组操作1:修改某历史版本的某一位置的元素操作2:查询某历史版本的某一位置的元素每次操作后都会有新的版本实现上还是采用主席树用线段树维护一个数组 主席树则维护了每个版本的线段树 动态开点,每个版本复制修改前的版本,只修改要修改的部分,空间为log */ #include <iostream>using namespace std;const int maxn = 1e6 + 5;int a[maxn],root[maxn],cnt;struct n

2020-08-27 21:50:39 196

原创 主席树总结

/*主席树的本质就是前缀的权值线段树维护n个权值线段树,第i个权值线段树表示[1...i]这些数构成的权值线段树对于第i个权值线段树,只需要用第i-1的根,再维护那个改变的值,所用的空间为log 查询区间第k小时用R的权值线段树减去L-1的权值线段树即可 */ //静态区间第k大 #include <iostream>#include <vector>#include <algorithm>using namespace std;const in

2020-08-27 11:36:10 116

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除