数据结构
入门
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 · 120 阅读 · 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 · 181 阅读 · 0 评论 -
中位数(洛谷p1168)(堆/树状数组+二分/线段树+二分)
题目地址注意偶数的情况堆构建两个堆,一个大根堆,一个小根堆,每次加入的时候,维护这两个堆,使得大根堆的个数在一定情况下比小根堆多1或者相等。 大根堆的最后一个元素即为中位数当上一次处理完:大根堆与小根堆个数相等。则下一次插入一定插入到大根堆。此时判断,小根堆的 堆顶>x 则将小根堆的堆顶元素插入到大根堆,小根堆pop,再把x压入小根堆。否则直接压入大根堆。大根堆与小根堆个数不相等与上面类似代码#include<iostream>#include<algorithm原创 2021-03-05 09:44:05 · 402 阅读 · 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 · 359 阅读 · 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 · 208 阅读 · 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 · 101 阅读 · 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 · 129 阅读 · 0 评论 -
一维树状数组(单点修改+区间查找 / 区间修改+单点查找 / 区间修改+区间查找)模板和例题
模板1题目地址模板2题目地址1:#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);#include<bits/stdc++.h>#define int long longusing namespace std;typedef pair<int,int> pii;typedef long long ll;const int INF = 0x3f3f3f3f;const double eps原创 2020-11-13 18:27:39 · 151 阅读 · 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 · 136 阅读 · 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 longusing namespace原创 2020-10-11 22:09:41 · 314 阅读 · 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 · 1454 阅读 · 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 · 805 阅读 · 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和x3g原创 2020-09-06 21:28:29 · 93 阅读 · 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 longusing namespace std;原创 2020-09-06 20:01:45 · 103 阅读 · 0 评论 -
acwing 145 supermarket (二叉堆,并查集)
题目地址采用贪心的思想:1:按时间从小到大排序。让快过期的物品先卖,后面处理是否要卖它。设我们已经按当前最优的情况选出来了t个,当前处理的物品时间过期为t时,我们判断选出来的物品中是否有比它小的,如果有,则替换。当前处理物品时间过期为>t时,我们直接加入。故可以用堆去维护最小的那个。2:按利润从大到小的排序。我们尽可能在过期的时候去卖它。对于一个物品,过期的时间为t,则我们尽量在t的时候去卖它,若当前t已经被预定了,则往前面找空位去卖。止于0。可以用并查集去维护这句话(若当前t已原创 2020-09-06 17:46:35 · 107 阅读 · 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 longusing namespace std;typedef pair<原创 2020-09-06 16:03:55 · 101 阅读 · 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)还有datap的data = max(ma原创 2020-09-02 00:01:13 · 72 阅读 · 0 评论