数据结构
入门
ddgo
给我高高飞起来啊!(ACM退役,转JAVA后端了)
展开
-
线段树2(洛谷p3373)(线段树)
题目地址 解释 多了一个乘法操作,可以考虑优先级。每次先算乘法。 首先,对于一个区间(和为s) 假设已经按 +a , 乘b进行了操作。值得到的值为( (s + a) * b )-> sb + ab 假设先乘得到(sb + a )这样相比,add应该还要再乘上一个b才对,所以,当更新到一个区间时, 为了进行先乘的操作而不让结果发生变化,应该将add乘上当前乘的值。 这个就是update里面更新乘法时候应该进行的操作。 push_down也是这样更新子区间的add,mul直接乘上。 初始状态mul为1原创 2021-03-06 14:07:26 · 146 阅读 · 0 评论 -
三元上升子序列(洛谷p1637)(树状数组/线段树)(扩展k元上升子序列)
题目地址 预处理l[i],r[i]表示左边比它小的和右边比它大的的个数。 显然,可以用树状数组或者线段树随着枚举,更新区间的值,然后查询一个区间的和,即可以得到l[],r[]。最后ans += l[i]*r[i]. 线段树 #include<iostream> #include<algorithm> #include<vector> using namespace std; const int N = 3e4 + 10; typedef long long ll; in原创 2021-03-05 14:33:41 · 198 阅读 · 0 评论 -
中位数(洛谷p1168)(堆/树状数组+二分/线段树+二分)
题目地址 注意偶数的情况 堆 构建两个堆,一个大根堆,一个小根堆,每次加入的时候,维护这两个堆,使得大根堆的个数在一定情况下比小根堆多1或者相等。 大根堆的最后一个元素即为中位数 当上一次处理完: 大根堆与小根堆个数相等。则下一次插入一定插入到大根堆。 此时判断,小根堆的 堆顶>x 则将小根堆的堆顶元素插入到大根堆,小根堆pop,再把x压入小根堆。否则直接压入大根堆。 大根堆与小根堆个数不相等与上面类似 代码 #include<iostream> #include<algorithm原创 2021-03-05 09:44:05 · 461 阅读 · 2 评论 -
最接近神的人(洛谷p1774)(逆序对三种求法)
题目地址 归并求逆序对。 下面两种方法均先处理离散化。 树状数组 求逆序对,倒序插入:插入一个,统计比它小的数量,即ask(1,a[i]-1)。 顺序也行ask要变 #include<iostream> #include<vector> #include<algorithm> using namespace std; const int N = 5e5 + 10; typedef long long ll; #define lowbit(x) (x & -x)原创 2021-03-04 20:06:52 · 370 阅读 · 1 评论 -
poj3468(线段树懒标记和树状数组实现区间修改,区间查询)
题目地址 树状数组 用差分维护序列后,求一个数的值d[p]为∑i=1pb[i]\sum_{i=1}^{p}b[i]∑i=1pb[i],求一个区间的值(1~p)为 ∑i=1p∑j=1ib[j]\sum_{i=1}^{p}\sum_{j=1}^{i}b[j]∑i=1p∑j=1ib[j] ,将其化简,得到∑i=1p(p−i+1)∗b[i]\sum_{i=1}^{p}(p-i+1)*b[i]∑i=1p(p−i+1)∗b[i],-> (p+1)∗∑i=1pb[i]−∑i=1p(b[i]∗i)(p+1)原创 2021-03-04 13:36:30 · 233 阅读 · 1 评论 -
检查边长度限制的路径是否存在 (并查集,排序,双指针) (LC)
题目地址 按询问的长度从小到大排序,并且按所有边从小到大排序。 对于第一个询问,把所有边长小于询问长度加入到一个集合,最后询问是否在在一个集合。 对于后面的的询问,保持当前已有的集合,继续往里面添加边长小于当前长度的点。 代码: class Solution { public: struct Node{ int a,b,c,d; bool operator <(const Node&T)const{ return c < T原创 2020-12-21 21:30:56 · 125 阅读 · 0 评论 -
acwing241楼兰图腾 (树状数组)
题目地址 与树状数组与逆序对的想法一样。 具体可以看博客 维护出每一个位置,左边有多少比它大的(n),右边有多少比它大的(m),这样可以知道,以这个点为最低点构成的v的数量。 维护操作: 统计左边有多少比它大的(n)。计算区间[a[i]+1,n]中出现元素的个数,更新,当前点的值为1. 表示这个点出现次数加1. 其它维护也类似。 #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #include<bits/stdc++.h&原创 2020-11-21 00:09:52 · 149 阅读 · 0 评论 -
一维树状数组(单点修改+区间查找 / 区间修改+单点查找 / 区间修改+区间查找)模板和例题
模板1题目地址 模板2题目地址 1: #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #include<bits/stdc++.h> #define int long long using namespace std; typedef pair<int,int> pii; typedef long long ll; const int INF = 0x3f3f3f3f; const double eps原创 2020-11-13 18:27:39 · 160 阅读 · 0 评论 -
食物链(并查集 扩展域 or 带权并查集)
题目地址1 题目地址2 注意,环形,假话不进行合并操作 对于每一类动物,一定会有三个域,同类域(x),捕食域(x+n),天敌域(x+n+n)。 给出两类动物,那么它们之间的关系: 1: x,y 为同一类。 既然为同一类,把x,y的每一个域合并一下就可以了。 2:x 吃 y ,则 x与y的天敌为一类, x的捕食域与y为一类,x的天敌类为y的捕食类。 冲突: 1: 当x,y为同一类的时候,显然下面一定不成立,x和y的捕食域在同一集合,y和x的捕食域在同一集合,x的天敌域与y在同一集合,y的天敌域与x在同一集合,原创 2020-10-30 17:36:28 · 146 阅读 · 0 评论 -
Jack Straws(叉积 + floyd / 并查集)
题目地址 判断线段是否相交 ab cd 用叉积的性质判断 a与cd,b与cd, c与ab,d与ab的关系(模板可以去找一下) 1 floyd 更新联通。 把枚举两两线段,判断是否相交,再用floyd去更新,推广出所有线段之间的联通关系。 代码: #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #include<bits/stdc++.h> #define int long long using namespace原创 2020-10-11 22:09:41 · 317 阅读 · 2 评论 -
巧克力块谜(二叉树的性质论证)
有一块n x m 格的巧克力,我们要把它切成n x m 个 1x1的小块,只能沿直线切,而且不能同时几块同时的切。 先只考虑一边,我们把它分成全是1. 对于任意的长度,都可以像二叉树那样分解(用网上的一种完全二叉树的定义来说下图即为完全二叉树)。如图 可以知道,分解的次数就为非叶子节点的个数,设为x . 则总点数为 2x+1 (完全二叉树的性质), 又由一个数可以分解成2n-1个点(归纳法) 故 x = n-1. 即 最少的操作次数为 m-1 + m*(n-1) = n*m-1. 后面 (n-1) *原创 2020-10-09 15:31:51 · 1496 阅读 · 0 评论 -
分治法解 最近点对问题 (画图证明)
1: 暴力枚举两两之间点的距离。 O(n^2); 2: 分治法。 与合并(归并)排序类似。 分解: 先把所有点按x 升序排序。 再取mid = (l+r) /2; 解决: 左右(返回d1,d2)两边分别递归下去,直到 1 或 2 可以直接返回值。 我们 取 mi = min(d1,d2); 表示当前最小的距离。 合并: 对于分开的两个区间,可能会存在着最短距离的两个点分别在分开的左右两边。所以我们要特殊处理这种情况。 我们按当前 l - r 的区间里面的点 按 y 升序排序(在这里我们可以运用归并排序的一部原创 2020-10-05 17:52:07 · 817 阅读 · 0 评论 -
acwing 239 poj 1733 (并查集 边带权 离散化)
用s[] 表示1的个数的前缀和 1: 当s[l-r] = even,则 s[l-1] 与 sum[r]奇偶性相同 2:当s[l-r] = odd,则 s[l-1] 与 sum[r]奇偶性相反 故可以将l-1 和 r 合并到一个集合,并且可以判断。 3种情况 x1与x2 同 ,x2与x3 同,则x1与x3同 同,不同,不同 不同,不同,同 故我们可以 令 偶数为 0,奇数为 1 它们的异或对应上面的哪些情况。 儿子节点与祖先节点的情况就是路径取个异或。//判断的时候就可以用祖先节点当x2 来判断x1和x3 g原创 2020-09-06 21:28:29 · 97 阅读 · 0 评论 -
acwing 238 银河英雄传说(并查集)
题目地址 维护size和距离的并查集。 用d[i]表示i到父节点的距离。 再合并的时候,子节点到合并的父节点的距离就是父节点的size。 求两个点在不在同一列就是求是否在同一个集合,,它们之间隔的距离就是它们分别到父节点的距离之差减1. #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #include<bits/stdc++.h> #define int long long using namespace std;原创 2020-09-06 20:01:45 · 111 阅读 · 0 评论 -
acwing 145 supermarket (二叉堆,并查集)
题目地址 采用贪心的思想: 1: 按时间从小到大排序。让快过期的物品先卖,后面处理是否要卖它。 设我们已经按当前最优的情况选出来了t个, 当前处理的物品时间过期为t时,我们判断选出来的物品中是否有比它小的,如果有,则替换。 当前处理物品时间过期为>t时,我们直接加入。 故可以用堆去维护最小的那个。 2: 按利润从大到小的排序。我们尽可能在过期的时候去卖它。 对于一个物品,过期的时间为t,则我们尽量在t的时候去卖它,若当前t已经被预定了,则往前面找空位去卖。止于0。 可以用并查集去维护这句话(若当前t已原创 2020-09-06 17:46:35 · 117 阅读 · 0 评论 -
acwing 237 程序自动分析(并查集)
题目地址 用 并查集将所有相关的(1)都合并到相关集合里面,再去判断所有不想关的(0)是否出现在同一个集合,若出现在同一个集合内的话说明矛盾。 要用离散化去离散i,j再用find去查找i,j离散后的位置。 #define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #include<bits/stdc++.h> #define int long long using namespace std; typedef pair<原创 2020-09-06 16:03:55 · 106 阅读 · 0 评论 -
acwing 245 Can you answer on these queries III【线段树】
题目地址 线段树模板加维护。 在build 和 change 中要维护一些东西。 区间和sum,区间的最大连续子段和data,靠左最大连续区间和lmax和靠右最大连续和rmax. 怎么维护: p = 父节点,l = 左节点,r = 右节点。 p的sum =l的sum + r的sum. p靠左最大连续区间和 lmax = max(l的lmax,l的sum+r的lmax). 同理 p靠右的最大连续区间和 rmax = max(r的rmax,r的sum+l的rmax) 还有data p的data = max(ma原创 2020-09-02 00:01:13 · 78 阅读 · 0 评论