线段树

线段树区间更新 + 离散化 -- Mayor's posters POJ - 2528

自闭症网瘾萝莉.ら 提交于 2020-02-23 01:38:18
Mayor’s posters POJ - 2528 题意: n(n<=10000) 个人依次贴海报,给出每张海报所贴的范围li 、ri(1<=li<=ri<=10000000)。求出最后还能看见多少张海报。 思路: 线段树区间更新题,可以用懒人更新的思路优化,对于线段树来说10000000显然太大,数组开不了,而n只有10000,就可以离散化一下。 但是离散化对本题来说有一个问题(坑), 就是由于我们是紧紧挨着压缩的, 所以可能会存在错误覆盖的问题 例如对于数据 3 1 10 1 3 7 10 我们压缩过后应该就变为 1 4 1 2 3 4 可这样的话我们目测一下, 就只有2个区间可以看到了, 第一个被盖住了. 而真正的答案应该是3才对 这是我们应该在离散化数组c中存储时考虑将每次的右边界r+1也存入, 这样就可以有效避免错误覆盖的问题。 问题code: # include <iostream> # include <stdio.h> # include <algorithm> using namespace std ; const int maxn = 1e5 + 5 ; int st [ maxn * 4 ] , vis [ maxn * 2 ] , cnt [ maxn * 2 ] , a [ maxn * 2 ] ; int ans ; void pushdown (

线段树 (lazy完全版)

谁说胖子不能爱 提交于 2020-02-22 16:28:24
#include <bits/stdc++.h> using namespace std; #define ll long long #define mem(a, b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define DBG printf("this is a input\n") #define fi first #define se second #define mk(a, b) make_pair(a,b) #define p_queue priority_queue ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); } ll lcm(ll a, ll b) { return a / gcd(a, b) * b; } struct node { int l , r; ll sum , lz; }tree[2000000]; ll n , m, input[100005]; void pushdown(int i) { if(tree[i].lz != 0) { tree[i*2].lz += tree[i].lz; tree[i*2+1].lz += tree[i].lz; int mid = (tree[i].l+tree[i].r)/2; tree[i*2

征服线段树之线段树的两种建树方式详解——自顶向下建树与自底向上建树 C/C++代码

时光怂恿深爱的人放手 提交于 2020-02-22 13:38:14
一、什么是线段树? 线段树就是把区间逐次二分得到的一种树状结构,所以它是一颗二叉树。 线段树适用于解决序列上的动态问题,经典问题如:动态区间查询统计问题,包括:区间查询(区间和、区间最值、最大公约、最小公倍等查询问题)、单点查询、单点修改、区间修改、区间K值查询等问题。 二、线段树的两种建树方式 1. 自顶向下构建线段树 (1)说明:完全根据定义,根结点为最大区间[0,n-1],向下不断二分区间,直到叶子结点[i,i],便可得到整颗线段树,建树过程有着很好的递归结构,一般使用递归建树。如图所示,以长度为8的序列构建一颗线段树,区间划分如下: (2) 便可以得到代码,以区间和为例(C++) #define MAX_N (int)(1e7+1) #define l(x) (x<<1) #define r(x) (x<<1|1) struct node{ int val; }; node dat[MAX_N];//dat[0]不存数 ,结点dat[1]为树根 /*自顶向下建树 O(nlogn) i:当前结点在线段树中的编号为i [l,r]:当前结点所维护的区间 */ void build(int i,int l,int r){ if(l==r){//叶子节点 cin>>dat[i].val; return; } int mid=(l+r)>>1; build(l(i),l,mid);/

树链剖分详解

给你一囗甜甜゛ 提交于 2020-02-22 06:44:30
  问题是这样的:对于一株树(无向无环连通图),为每个结点分配对应的权重。要求能高效计算任意两个结点之间的路径的各类信息,其中包括路径长度(路径上所有结点的权重加总),路径中最大权重,最小权重等等。到这里一切都还是比较简单的,我们可以利用Tarjan的LCA算法在线性时间复杂度内快速求解。但是如果还要求允许动态修改任意结点的权值,那么问题就不简单了。很容易发现这有些类似于线段树的问题,但是线段树是作用在区间上,而我们的问题是发生在树上的,因此线段树并不适用。而树链剖分则是可以用于求解这类问题的高效算法,其更新权值的时间复杂度为O(log2(n)),而统计路径信息的时间复杂度为O((log2(n))^2)。下面对树链剖分进行讲解。   对于任意一株树,我们记r.size表示以结点r为根的子树中的结点总数,称为r的大小。记r.next表示r的所有子结点中size属性最大的一个结点(如果没有子结点允许留空),称为r的重孩子,而其余子结点称为r的轻孩子,与重孩子相连的边称为重边,而与轻孩子相连的边称为轻边。利用深度优先搜索算法可以在O(n)时间复杂度内计算所有结点的size和next属性。   很容易发现通过将每个结点与其重孩子通过一条特殊的链条连接,那么我们就在图中建立了多条互不相交的链路,每个结点都处于一个链路中(链路可能只有一个结点),这些链路称为重链。每一条重链中所有结点深度不同

线段树

自古美人都是妖i 提交于 2020-02-20 06:45:57
# include <bits/stdc++.h> # define inf 0x3f3f3f3f const int maxn = 1e5 + 10 ; using namespace std ; int Sum [ maxn << 2 ] ; //A[maxn<<2];//Sum求和,A为原数组(根据题目更改) int num [ maxn << 2 ] ; int len ; void PushUp ( int node ) //向上更新节点信息 { Sum [ node ] = Sum [ node << 1 ] + Sum [ node << 1 | 1 ] ; } void pushdown ( int node , int wide ) { if ( num [ node ] ) { int t = num [ node ] ; num [ node << 1 ] = t ; num [ node << 1 | 1 ] = t ; Sum [ node << 1 ] = ( wide - ( wide >> 1 ) ) * t ; Sum [ node << 1 | 1 ] = ( wide >> 1 ) * t ; num [ node ] = 0 ; } } void Build ( int l , int r , int node ) { //[l,r

线段树基础题目解析

放肆的年华 提交于 2020-02-19 17:23:45
一般的模板:区间加乘改,求区间极大 / 极小 / 和   线段树模板 1:区间加,求区间和 / 最大 / 最小     区间里的元素如果逐个修改就太慢了,所以考虑更快的方式——“懒惰标记”。     对于一个区间,只需要在下传时,遇到一个完整区间就标记并退出,并对走过的区间进行懒标记。     查询的时候,再在求和之前把懒标记加回来,就可以实现求和。   线段树模板 2:区间加,区间乘,求区间和 / 最大 / 最小     对于这种情况,标记下传的操作需要进行修改。     原来,做一次加法只需要这个区间的和懒标记加上这个值,并且让这个区间的求和数组加上 这个数的值*区间长度 。     但是现在,又多了一个乘法懒标记,在实现区间加、区间乘操作时会麻烦一些:     乘法懒标记数组清空时要赋值 1;     区间加时,不用任何改动;     区间乘时,不仅求和数组和乘法懒标记要乘上这个数,连加法懒标记也要乘上它才可以。   线段树模板 3:区间加,区间改,求区间和 / 最大 / 最小     区间改可以无视之前做过的任何操作,所以区间改时所有的懒惰标记都要改,当修改懒标记没有存储数时,最好存 -1 或不出现的数。 线段树趣题   ① 01 数列区间异或,区间求和      区间异或其实也不会难,只需要碰到完整的区间时将整个区间的和改成 区间长度 - 原区间和 ,其它类似于上面的题目

BZOJ 3545: [ONTAK2010]Peaks

守給你的承諾、 提交于 2020-02-18 14:53:37
支持离线 边和询问都按权值排序,然后扫描线对每一条边进行处理,将小于等于当前询问权值的边进行处理 加入一条边相当于合并两个连通块,用并查集维护根,线段树合并两个根处的线段树即可 查询就在根查询权值线段树的第 \(k\) 大 把递归版的线段树换成循环的trie的写法,跑得更慢了。。 #include <bits/stdc++.h> #define lp tree[p].l #define rp tree[p].r #define rq tree[q].r #define lq tree[q].l #define mid ((l + r) >> 1) char buf[1 << 21], *p1 = buf, *p2 = buf; inline char getc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++; } inline int read() { int x = 0, f = 1; char ch = getc(); while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getc(); } while (ch >= '0' && ch <= '9') { x = x *

【BZOJ4919】[Lydsy六月月赛]大根堆 线段树合并

倖福魔咒の 提交于 2020-02-17 11:30:09
【BZOJ4919】[Lydsy六月月赛]大根堆 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点。每个点有一个权值v_i。 你需要将这棵树转化成一个大根堆。确切地说,你需要选择尽可能多的节点,满足大根堆的性质:对于任意两个点i,j,如果i在树上是j的祖先,那么v_i>v_j。 请计算可选的最多的点数,注意这些点不必形成这棵树的一个连通子树。 Input 第一行包含一个正整数n(1<=n<=200000),表示节点的个数。 接下来n行,每行两个整数v_i,p_i(0<=v_i<=10^9,1<=p_i<i,p_1=0),表示每个节点的权值与父亲。 Output 输出一行一个正整数,即最多的点数。 Sample Input 6 3 0 1 1 2 1 3 1 4 1 5 1 Sample Output 5 题解 :考虑用f[i][j]表示在i节点的子树中,最大值<=j,最多能选择多少点。如何转移呢?父亲节点的f数组可以看成儿子节点的f数组对应位置相加。然后再用 当前点权值-1处的f值 +1 来更新当前点权值后面的所有f值。 为此,我们可以考虑用线段树+标记永久化维护,我们要实现维护区间最大值。然后转移的时候可以直接用线段树合并搞定。细节还是比较多的。 upd:多说一点吧。有标记的线段树进行合并时也是比较恶心的。对于区间max标记

数据结构笔记

回眸只為那壹抹淺笑 提交于 2020-02-17 11:29:17
目录 数据结构 二叉搜索树 线段树 动态开点 线段树的合并 线段树优化建图 做法 例题 并查集 按秩合并 二分图判定 字典树 用字典树解决异或问题(01Trie) 字符串hash 双hash 进制hash 如何得到一个字符串所有子串的hash st表 倍增 lca转换为RMQ问题 tarjan算法离线求lca 一个复杂度的证明 非旋转treap即可持久treap 数据结构 二叉搜索树 递归定义 它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉搜索树。 •维护一个集合,支持操作:插入、删除、查找 •方法:建立一棵有序的二叉树,每个结点对应集合中一个元素。 •满足性质:结点u的左子树的结点权值都比u小,右子树的结点权值都比u大。 •插入、删除、查找只需在二叉树中按照权值往下走即可。 可能的问题: 可能退化成一条链(例如如果按升序插入),那么每次操作平均复杂度O(n)需要一些技巧让二叉搜索树保持平衡。STL中的set和map都是平衡的二叉搜索树。noip一般情况下够用。 线段树 护区间信息的数据结构 每个结点对应一个序列的区间 完全二叉树,左子树为左一半区间,右子树为右一半 单点/区间修改。 动态开点 例题 维护一个数据结构

【转】acm学习方法

混江龙づ霸主 提交于 2020-02-16 11:35:11
建议 做到50行以内的程序不用调试、100行以内的二分钟内调试成功. acm主要是考算法的,主要时间是花在思考算法上,不是花在写程序与debug上。 算法集锦 https://www.cnblogs.com/ngyifeng/p/3718601.html 书籍推荐 入门三本: 《数据结构与算法》(傅清祥,王晓东编著,我所见过的最好的算法教材) 程序设计导引及在线实践 作者: 李文新 ACM程序设计培训教程 吴昊 基础提高: 算法设计与分析 这是国内牛人王晓东的大作,非常不错的算法书 算法设计与试验题解 王晓东 计算几何-算法设计与分析 周培德 组合数学 第三版 冯舜玺 译 算法艺术与信息学竞赛 刘汝佳的杰作,引导着信息学竞赛的发展 如果算法导论是九阳神功,那这本无疑就是九阴真经。本书是专为参加一些诸如ACM之类程序设计比赛的同学而写的,江湖人称“黑书”。里面讲的都是一些在编程比赛中常用的算法、数据结构,以及一些数论和计算几何等。我虽然并不搞竞赛,但也从此书中受益颇多。 国际信息学奥林匹克竞赛指导— — 实用算法的分析与程序设计  吴文虎 王建德 Introduction to Algorithm 科曼著 传说中的宝典 算法导论(原书第3版) Algorithms 算法概论 短小精悍,别据一格,准经典之作。一个坏消息: 同算法导论,该书没有习题答案。好消息:习题很经典,难度也适中