线段树

K - Atlantis (线段树+扫描线)

自闭症网瘾萝莉.ら 提交于 2019-12-02 17:06:49
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity. InputThe input file consists of several test cases. Each test case starts with a line containing a single integer n (1<=n<=100) of available maps. The n following lines describe one map each. Each of these lines contains four

主席树

安稳与你 提交于 2019-12-02 16:52:47
目录: 个人理解 时空复杂度分析 应用及例题 拓展 一、个人理解: 主席树 的全称是 可持续化权值线段树 ,是一种可以维护静态区间第K小的高级数据结构。 主席树的主要思想就是:保存每次插入操作时的历史版本,以便查询区间第 \(k\) 小。 因为主席树每次都要插入操作,所以是不能用 堆式建树 的( rt<<1 , rt<<1|1 ),所以我们使用 动态开点线段树 ,并用 ls[] 和 rs[] 保存当前节点的左右儿子。 联系 前缀和 ,可以预处理达到 \(O(1)\) 的时间复杂度。我们发现主席树也满足这个性质,所以若需要统计 \([l,r]\) 的信息,只需要 \(O(1)\) 查询 sum[r]-sum[l-1] 即可。 二、时空复杂度分析: 时间复杂度: 同线段树的时间复杂度: \(O(n\text{log}n)\) 空间复杂度: 我们是动态开点,所以一颗线段树只会出现 \(2n-1\) 个节点,而每次插入会增加 \(O(n\text{log}n)\) 个节点,则最坏情况下会有 \(2n-1+O(n\text{log}n)\) 个节点。故空间复杂度为: \(O(n\text{log}n)\) 。 在实际运用的时候, ls[] , rs[] , sum[] 等数组都需要开 \(2^5\) 倍空间,即 MAXN<<5 ( MAXN 为 \(n\) 的值域)。 注

[线段树系列] 普通线段树

戏子无情 提交于 2019-12-02 16:40:38
线段树是一种强大的数据结构,用于维护区间、图、树等各种数据。 线段树的“强大”体现在它面对各种类型的数据都有应付的方式,而且不断有“改进”版线段树的产生。 线段树是基于递归和分治思想的数据结构,一般用于维护具有“区间可加性”的数据。 什么是”区间可加性“呢,举几个例子: 区间和,区间最大最小值,区间LCA,区间质数个数 这些东西都有共同的特性:f(x,y)=f(f(x,z),f(z,y)),z∈[x,y] 于是我们就可以用线段树来维护。 随手画了张线段树的图,它大概长这样: 是不是很神奇? 它是怎么维护数据的呢?( 以维护区间数据为例 ) 让我们用区间最大值为例: 假设原数组a是{1,2,3,4,5,6} (我习惯下标从1开始) 我们把原数组插入线段树,看看它各个节点的值: 假设我们要查询区间 [2,4] 的值: 我们发现并没有 [2,4] 这个节点,那怎么查询呢? 我们计算出 [2,4] 的mid值,mid=(l+r)/2=3。 然后我们查询区间 [2,3] 和区间 [4,4] ( 即区间[l,mid]和区间[mid+1,r] )。 区间 [4,4] 是叶子节点,返回它的值4。 回到 [2,3] 我们继续递归计算max( [2,2],[3,3] )返回3 得到最后的最大值4 这一段的代码: int query(int p,int l,int r){ if(l<=l(p) && r

线段树(标记下传乘法和加法)

时光总嘲笑我的痴心妄想 提交于 2019-12-02 16:21:19
传送门: https://www.luogu.org/problem/P3373 标记下传,这种东西就是在求和和更改的时候进行pushdown把标记(各种标记,类似于寒冰标记、痛苦标记、穹妹标记……)下传,来节省时间。 还是挺简单的,主要问题处在pushdown上但多看看就会了 #include<bits/stdc++.h> using namespace std; long long n,m,p; long long multag[1000009]; long long addtag[1000009]; long long seg[4000009]; long long num[1000009]; inline long long kd() { long long x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();} return x*f; } inline long long ls(long long x){return x<<1;} inline long long rs(long long x){return x<<1|1;} void build(long

Peaks 线段树合并

孤街浪徒 提交于 2019-12-02 15:44:51
Peaks 线段树合并 \(n\) 个带权值 \(h_i\) 山峰,有 \(m\) 条山峰间双向道路, \(q\) 组询问,问从 \(v_i\) 开始只经过 \(h_i\le x\) 的路径所能到达的山峰中第 \(k\) 高的山峰,如果无解输出 \(-1\) 线段树合并好题。 吊打主席树、Kruskal重构树的典范 首先发现可以离线,我们将所有询问按 \(x\) 排序,随着询问再去加边,这样可以去掉路径上 \(h_i\le x\) 这一条件使问题极大简化。 然后从 \(v_i\) 开始能经过的所有山峰可以看做联通块,于是我们愉快地用并查集维护,用权值线段树查询第 \(k\) 大,合并联通块时合并权值线段树即可。很像 [HNOI2012]永无乡 。 另外注意此题是查询第 \(k\) 大,不是第 \(k\) 小。 #include <cstdio> #include <algorithm> #define MAXN 100010 #define MAXM 500005 using namespace std; int n,m,q; inline int read(){ char ch=getchar();int s=0; while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') s=s*10+ch-'0', ch

线段树合并(模板)

雨燕双飞 提交于 2019-12-02 12:49:23
线段树合并的原理比较简单,这里贴一下模板。 基本结构就是: int hb(int x1,int x2) { 1、若x1、x2是叶子节点,那么将x2合并到x1 2、若x1的左儿子为空,x2的左儿子不为空,那么将x1的左指针指向x2的左儿子;若x1、x2的左儿子都不为空那么继续合并它们的左儿子 3、右儿子同上 4、f[x1]=f[x1的左儿子]……f[x1的右儿子](更新f[x1]) } 在贴一个例子(以f[x]=f[lson]+f[rson]为例): int hb(int z1,int z2) { if(f[z1].l==f[z1].r){f[z1].v|=f[z2].v;return 0;} if(f[z1].ls==0&&f[z2].ls!=0)f[z1].ls=f[z2].ls; else if(f[z1].ls!=0&&f[z2].ls!=0)hb(f[z1].ls,f[z2].ls); if(f[z1].rs==0&&f[z2].rs!=0)f[z1].rs=f[z2].rs; else if(f[z1].rs!=0&&f[z2].rs!=0)hb(f[z1].rs,f[z2].rs); f[z1].v=f[f[z1].ls].v+f[f[z1].rs].v; } 来源: https://blog.csdn.net/chiyankuan/article/details

P5490 【模板】扫描线

依然范特西╮ 提交于 2019-12-02 12:39:16
题目地址 注意点: 线段树中使用获取具体长度时右端点应当+1,向线段树内插入值时右端点应当-1.(区间覆盖线段树) #include<cstdio> #include<iostream> #include<algorithm> #define ll long long using namespace std; const int MAXN=2e6+50; struct Line{ ll x1,x2; ll y; bool type;//0:出现 1:删除 bool operator <(Line another)const{ return y<another.y; } }lines[MAXN]; int lineCnt=0; void addLine(ll x1,ll x2,ll y,bool type){ lines[++lineCnt].x1=x1; lines[lineCnt].x2=x2; lines[lineCnt].y=y; lines[lineCnt].type=type; } struct Node{ int l,r; ll len,cnt;//长度 覆盖次数 }tr[MAXN*4]; int root=1; void build(int p,int l,int r){ tr[p].l=l,tr[p].r=r; if(l==r)return; int mid=(l

线段树 模板

纵然是瞬间 提交于 2019-12-02 12:25:00
原创建时间:2018-04-01 00:26:09 快速查找和修改区间 注:本文包含 洛谷 P3372 【模板】线段树 1 题解 线段树模板 前言 什么是线段树? 线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。 线段树的主要用途及好处? 线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。 线段树的应用? 最简单的应用就是记录线段是否被覆盖,随时查询当前被覆盖线段的总长度。 代码 基础函数 我们选择一个$O(1)$的取儿子函数: inline int leftChild(int p) { return p << 1; } // 左子树 inline int rightChild(int p) { return p << 1 | 1; } // 右子树 线段树的维护: void pushUp(int p) { t[p] = t[leftChild(p)] + t[rightChild(p)]; } // 向上维护区间 void pushUpMin(int p) { t[p] = std::min(t[leftChild(p)], t[rightChild(p)]); } // 向t[p]下放Min标签 void pushUpMax(int p) { t[p] = std::max(t

线段树模板

筅森魡賤 提交于 2019-12-02 12:24:14
区间修改: #include<bits/stdc++.h> using namespace std; const int N=1e5+5; int sum[N<<2],lazy[N<<2],a[N]; void pushup(int rt) { sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void pushdown(int l,int r,int rt) { if(lazy[rt]==0)return; lazy[rt<<1]+=lazy[rt]; lazy[rt<<1|1]+=lazy[rt]; int mid=(l+r)>>1; sum[rt<<1]+=(mid-l+1)*lazy[rt]; sum[rt<<1|1]+=(r-mid)*lazy[rt]; lazy[rt]=0; } void build(int l,int r,int rt) { lazy[rt]=0; if(l==r) { sum[rt]=a[l]; return; } int mid=(l+r)>>1; pushdown(l,r,rt); build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); pushup(rt); } void update(int L,int R,int val,int l,int r,int rt) { if(L<=l&&r<

CF413E Maze 2D 线段树

有些话、适合烂在心里 提交于 2019-12-02 11:54:29
CF413E Maze 2D ### 线段树 题目 宽度只有 \(1\) 的话怎么做? 用线段树维护一下 \(dis\) 表示 \(l-r\) 区间的距离 那么宽度为 \(2\) 的也一样啊 就可以设四个距离 表示左上到右上,左上到右下,左下到右上,左下到右下 这样就可以查询了 #include<bits/stdc++.h> using namespace std; const int maxn=2*1e5+10,inf=0x3f3f3f3f; int n,m,tu[10][maxn]; struct tree{ int dt[5];//左上到右上 左上到右下 左下到右上 左下到右下 }tr[maxn<<2]; inline void pushup(int p){ tree ls=tr[p<<1],rt=tr[p<<1|1]; tr[p].dt[1]=min(inf,min(ls.dt[1]+rt.dt[1],ls.dt[2]+rt.dt[3])+1); tr[p].dt[2]=min(inf,min(ls.dt[1]+rt.dt[2],ls.dt[2]+rt.dt[4])+1); tr[p].dt[3]=min(inf,min(ls.dt[3]+rt.dt[1],ls.dt[4]+rt.dt[3])+1); tr[p].dt[4]=min(inf,min(ls.dt[4]+rt