![](https://img-blog.csdnimg.cn/20201014180756927.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
高级数据结构
图一乐图一乐
这个作者很懒,什么都没留下…
展开
-
acwing2847. 老C的任务(cdq分治求三维偏序)
思路:求一个矩阵内的点数可以用二维前缀和求出,那么二维前缀和就是求左下方的点的数量,也就是存在偏序关系xi<xj,yi<yj,那么直接上cdq分治求偏序关系。const int N = 6e5 + 100;struct node { int x, y, z; ll p; int id, fg; ll sum; bool operator<(const node& b)const { if (x != b.x)return x < b.x; if (y !原创 2021-03-04 20:45:22 · 140 阅读 · 1 评论 -
C. Sasha and Array(线段树+矩阵快速幂)
题意:给出一个序列a,给出两种操作,操作1:对a数组中[l,r][l,r][l,r]范围的内的数加上一个数x,操作2:查询[l,r][l,r][l,r]范围内的f[a[i]]f[a[i]]f[a[i]],其中f[x]f[x]f[x],是指第x个斐波那契数。思路:显然对于第一种操作,这里需要用到区间修改,所以要用到懒标记的线段树,对于第二种操作,可以很快地想到用矩阵加速递推式。于是开一个结点信息是矩阵的线段树,维护每个点的斐波那契和,懒标记写成转移矩阵的幂次,就可以非常清晰做出来这题。const int原创 2020-11-11 11:00:21 · 148 阅读 · 0 评论 -
P1117 [NOI2016]优秀的拆分(后缀数数 or hash+差分)
思路:直接上后缀数组可以通过求lcp把本来的问题从N3N^3N3降到N2N^2N2,但是这样还是有4.5e8的复杂度,只能95分。再次考虑优化。假设在枚举AABB中A的长度len时,考虑对字符串按照len进行分块,例如len=2,把s=“abababab”,分成s=“ab ab ab ab”,这样len为2的A顶多出现在两个块中,然后考虑前后拼接,维护一个正向的后缀数组,一个反向的后缀数组,这样在枚举每一段时就可以知道然后就在每次枚举相邻的两个块,求lcp,lcs,差分记录对区间的贡献。总结:多造样例,原创 2020-10-27 15:04:30 · 191 阅读 · 0 评论 -
P1972 [SDOI2009]HH的项链(区间不同颜色数量)
const int N = 1e6 + 5;int tree[N],n;void add(int k, int num){ for (int i = k;i <= n;i += i & -i) tree[i] += num;}int read(int k){ int sum = 0; for (int i = k;i > 0;i -= i & -i) sum += tree[i]; return sum;}struct node{ int l,原创 2020-10-13 11:56:29 · 135 阅读 · 0 评论 -
D - Petya and Array(树状数组,二分)
思路:对于al+..ara_l+..a_ral+..ar这种区间和问题一般都要考虑前缀差,然后问题就转化为了求sum[r]−sum[l−1]<tsum[r]-sum[l-1]<tsum[r]−sum[l−1]<t,对等式移项sum[r]−t<sum[l]sum[r]-t<sum[l]sum[r]−t<sum[l],然后又发现是要查询有几个前缀大于当前的前缀减去t,所以用树状数组把前序的前缀存起来,这里数据是1e9,所以判断大小不能直接比大小,用到排序,比较相对大小。还原创 2020-07-17 09:57:50 · 237 阅读 · 0 评论 -
HDU 3974 Assign the task(树)
题意:有n个人,给出n-1种属于关系,形成一颗阶层树,如果上级收到的任务,所有它的子树和它本身都将从事这任务。给出两种操作,第一:分配给x任务y,第二:查询x当前做的任务。思路:在向上找祖先的过程中,维护更新时间最晚的人的任务号。const int N = 5e4 + 5;int t;struct node{ int lasttime; int task;}e[N];int fa[N];int main(){ //freopen("in.txt", "r", stdin); int原创 2020-07-05 09:41:04 · 74 阅读 · 0 评论 -
Tunnel Warfare(树状数组+二分)
const int N =5e4+5;int t;int n, m;int tree[N];void add(int k, int num) { for (int i = k;i <= n; i += i & -i) tree[i] += num;}int read(int k){ int sum = 0; for (int i = k;i > 0; i -= i & -i) sum += tree[i]; return sum;}bool vi原创 2020-07-04 10:25:29 · 174 阅读 · 0 评论 -
Can you answer these queries?(无需懒标记的区间修改)
注意:并不是所有的区间修改需要懒标记,如果复杂度不高,可以直接单点改。ll w[N];struct node{ int l, r; ll sum;}tr[N*4];void pushup(int u){ tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;}void build(int u, int l, int r){ if (l == r)tr[u] = { l,l,w[l] }; else { tr[原创 2020-07-03 20:57:31 · 89 阅读 · 0 评论 -
Just a Hook HDU - 1698(区间修改)
注意:懒标记传递到下层后一定要清空当层的。const int N = 1e5+5;int t;int n, m;struct node{ int l, r, sum, v;}tr[N*4];void pushup(node &root, node &le, node &re){ root.sum = le.sum + re.sum;}void pushup(int u){ pushup(tr[u], tr[u << 1], tr[u <&l原创 2020-07-02 21:10:08 · 101 阅读 · 0 评论 -
AcWing 1277. 维护序列(懒标记模板题)
理解:懒标记只可能存在线段树的一层中,当子节点接受懒标记时,父节点完成更新任务,清除懒标记。const int N = 1e5 + 5;int t;int m, n, p;int w[N];struct node{ int l, r; ll sum, add, mul;}tr[N*4];void pushup(int u){ tr[u].sum = (tr[u << 1].sum + tr[u << 1 | 1].sum) % p;}void change原创 2020-07-02 15:41:07 · 115 阅读 · 0 评论 -
AcWing 243. 一个简单的整数问题2(pushdown模板题,区间加数,区间求和)
思想:访问到树中结点时不再下降,查询时再更新。const int N = 1e5 + 5;int t;int w[N];struct node{ int l, r; ll sum, add;}tr[4*N];void pushup(int u){ tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;}void pushdown(int u){ node &root = tr[u], &le =原创 2020-07-02 10:14:58 · 86 阅读 · 0 评论 -
D2. Optimal Subsequences (Hard Version)(贪心,树状数组,二分)
题意:给个序列n,给m次操作,每次操作输入k,pos,求原序列长度为k的子序列(子序列满足是所有长度为k的子序列中和最大的,和相同的情况下,取字典序小的)中第pos个元素的值。思路:选k个元素,要求和最大,肯定是从大的元素开始选,而对于元素大小相同的元素,取坐标小的,这样字典序是小的。然后将m次操作,按k从小到大进行排序,这样可以维护一个有关元素坐标的树状数组,对于求第pos个元素,可以利用树状数组+二分求第pos个元素的下标。int n, m;int tree[N];void add(int k,原创 2020-06-07 11:56:31 · 314 阅读 · 0 评论 -
D. Distinct Characters Queries(二分or树状数组)
题意:给个字符串,给两种操作,操作1:将字符串的第pos个字符值改成c,操作2:求[l,r]中的不同的字符数量。1.自己的思路开26个数组记录每个字符出现的位置,对于操作1,二分找到要在原字符的数组中删除的位置,二分找到在新字符的数组中插入的位置。对于操作2,对于26个字符分别二分,求出是否存在[l,r]之间的。然后效率比较慢,2000ms的题目勉强1800ms过了。**vector<vector<int> > v(26);int main(){ string s; c原创 2020-06-06 23:16:41 · 161 阅读 · 0 评论 -
AcWing 246. 区间最大公约数
结论:gcd(AL,AL+1,AL+2,...,AR)=gcd(AL,AL+1−AL,AL+2−AL+1,...,AR−AR−1)gcd(A_L,A_{L+1},A_{L+2},...,A_R)=gcd(A_L,A_{L+1}-A_L,A_{L+2}-A_{L+1},...,A_R-A_{R-1})gcd(AL,AL+1,AL+2,...,AR)=gcd(AL,AL+1−AL,AL+2−AL+1,...,AR−AR−1)所有用线段树维护前缀和差分。这样操作1就从区间修改转化成了单点修原创 2020-06-05 21:25:28 · 116 阅读 · 0 评论 -
AcWing 245. 你能回答这些问题吗
struct node{ int l, r; int tmx, lmx, rmx, sum;}tr[4*N];int a[N];void pushup(node &u, node &l, node &r){ u.tmx = max(max(l.tmx, r.tmx), l.rmx + r.lmx); u.lmx = max(l.lmx, l.sum + r.lmx); u.rmx = max(r.rmx, l.rmx + r.sum); u.sum = l.su原创 2020-06-05 13:40:26 · 114 阅读 · 0 评论 -
AcWing 1275. 最大数
题意:给两种操作。添加操作:向序列后添加一个数,序列长度变成 n+1;询问操作:询问这个序列中最后 L 个数中最大的数是多少。思路:线段树裸题,通过单点修改和回溯中的pushup维护区间最大值。struct node{ int l, r, w;}tr[4*N];void pushup(int u)//由子节点信息来计算父节点信息{ tr[u].w = max(tr[u << 1].w, tr[u << 1 | 1].w);}void build(int u,原创 2020-06-04 21:11:35 · 154 阅读 · 0 评论 -
E. Little Elephant and Inversions(树状数组,双指针,*2400)
总结:没看题解写的,感觉自己写的有些繁琐,应该加强分析在敲的。思路:先预处理出每个点对整个序列逆序对的贡献,及前序比当前点大的以及后序比当前点小的。如果整个序列的逆序对小于k,直接输出全部解。然后就双指针,维护一个区间保证至少减去k-sum个逆序对,记录每个左指针下,右指针的最左。ll k;int n, tree[N],tree2[N],tree3[N];void add(int k, int num) { for (int i = k;i <= n; i += i & -i)原创 2020-05-19 15:09:20 · 135 阅读 · 0 评论 -
AcWing 241. 楼兰图腾
树状数组可以计算之前插入的数有几个比当前数小,有几个比当前数大,也就是可以知道当前数是第k小。int n, tree[N];void add(int k, int num) { for (int i = k;i <= n; i += i & -i) tree[i] += num;}int read(int k){ int sum = 0; for (int i = k;i > 0; i -= i & -i) sum += tree[i]; retu原创 2020-05-18 21:41:15 · 150 阅读 · 0 评论 -
D. Multiset(树状数组+二分)
int tree[N];int n, q, x;void add(int k, int num) { for (int i = k;i <= n; i += i & -i) tree[i] += num; }int read(int k){ int sum = 0; for (int i = k;i > 0; i -= i & -i) sum += tree[i]; return sum;}inline int in(){ char ch原创 2020-05-18 09:01:45 · 318 阅读 · 2 评论