线段树

Mayor's posters(线段树+离散化+lazy)

风格不统一 提交于 2020-02-08 10:08:18
Mayor's posters(线段树+离散化+lazy) 题目大意: 在墙上贴海报,然后很多海报,一层又一层,问你最后可以看到多少张海报。 题目分析: 数据范围很大,普通的线段树肯定超时+超内存,所以要用到离散化,离散化有基础的和稍微复杂一点的,然后这题要用到稍微复杂一点的, 离散化简单的来说就是只取我们需要的值来用,比如说区间[1000,2000],[1990,2012] 我们用不到[-∞,999][1001,1989][1991,1999][2001,2011][2013,+∞]这些值,所以我只需要1000,1990,2000,2012就够了,将其分别映射到0,1,2,3,在于复杂度就大大的降下来了 所以离散化要保存所有需要用到的值,排序后,分别映射到1~n,这样复杂度就会小很多很多 而这题的难点在于每个数字其实表示的是一个单位长度(并且一个点),这样普通的离散化会造成许多错误(包括我以前的代码,poj这题数据奇弱) 给出下面两个简单的例子应该能体现普通离散化的缺陷: 1-10 1-4 5-10 1-10 1-4 6-10 普通离散化后都变成了[1,4][1,2][3,4] 线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢? 例子一是完全被覆盖掉了,而例子二没有被覆盖 为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10]

蒟蒻林荫小复习——关于有限制区间元素查询的一些解法

我是研究僧i 提交于 2020-02-08 03:03:57
如题:本文主要说明对于区间有限制查询的一些解法(其实就两种) 问题1:给定一个数列,要求查询区间L—R中所有大于等于Va小于等于Vb的元素和 解法: 1.线段树套权值线段树 第一维维护区间,第二维作为权值线段树,维护值域在A—B之间的元素之和 每次查询就从第一维拉到对应区间,然后用Va和Vb确定在权值线段 树中的查询范围即可 2.分块 分块数组记为a,对每一个a块都开一个数组b,b数组将a块中元素拷贝后排序,新建c,对于每一个b都求前缀和 这样对于整块而言,用二分确定Va和Vb在b数组中的位置Ia,Ib,那么在这个数组的贡献即为c[lb]-c[la-1]. 零散部分暴力,不会超过2*sqrt(n) 问题2:在1的基础上求元素的个数 解法: 1.线段树套权值线段树 几乎同上,在第二维权值线段树中维护元素的个数即可(可能要离散化) 2.分块 分块数组记为a,对每一个a块都开一个权值数组b,b记录a中每种元素出现个数 b的范围为MinV—MaxV(离散化),对于每个b新开一个c记录b数组的前缀和 假设离散化后的Va,Vb为map[Va],map[Vb],则整块的贡献为c[map[Vb]]-c[map[Va]-1] 问题3:在1和2的基础上添加修改条件:可以是删去某一个元素(正常出题人应该不会这样搞),将某一个元素的值修改 解法: 1.线段树套权值线段树 大概方法同上

hdu5306(线段树+区间取最值)jls线段树

我只是一个虾纸丫 提交于 2020-02-08 00:25:56
jls论文: 根据上面论文我们就可以做这题了。 终于学会了jls线段树。 手敲了下,看懂理论1h,写+bug就花了不到1h。 果然线段树我还是比较熟练的 马上搞下camp树套jls树。。。 #include<bits/stdc++.h> using namespace std; #define ls o*2 #define rs o*2+1 typedef long long ll; const int M=1e6+7; ll mx[M<<2];//最大值 ll se[M<<2];//次大值 ll nm[M<<2];//最大值个数 ll sm[M<<2];//区间和 ll lz[M<<2];//懒标记,即该区间要与lzo 取min ll a[M]; void pu(int o,int l,int r)//合并左右子树 { sm[o]=sm[ls]+sm[rs]; mx[o]=max(mx[ls],mx[rs]); se[o]=max(se[ls],se[rs]); nm[o]=0; if(mx[ls]!=mx[rs]) se[o]=max(se[o],min(mx[ls],mx[rs])); if(mx[o]==mx[ls]) nm[o]+=nm[ls]; if(mx[o]==mx[rs]) nm[o]+=nm[rs]; } void bd(int o,int l,int r) {

线段树

笑着哭i 提交于 2020-02-07 22:40:48
线段树模板 struct SegmentTree { int l, r; int dat; } t[SIZE * 4]; // struct数组存储线段树 void build(int p, int l, int r) { t[p].l = l, t[p].r = r; // 节点p代表区间[l,r] if (l == r) { t[p].dat = a[l]; return; } // 叶节点 int mid = (l + r) / 2; // 折半 build(p*2, l, mid); // 左子节点[l,mid],编号p*2 build(p*2+1, mid+1, r); // 右子节点[mid+1,r],编号p*2+1 t[p].dat = max(t[p*2].dat, t[p*2+1].dat); // 从下往上传递信息 } build(1, 1, n); // 调用入口 void change(int p, int x, int v) { if (t[p].l == t[p].r) { t[p].dat = v; return; } // 找到叶节点 int mid = (t[p].l + t[p].r) / 2; if (x <= mid) change(p*2, x, v); // x属于左半区间 else change(p*2+1, x, v); //

线段树板子 http://poj.org/problem?id=3468

对着背影说爱祢 提交于 2020-02-07 15:15:44
#include <cstring> #include <cstdio> #include <algorithm> #include <cmath> #include <cstdlib> #include <vector> #include <iostream> #define lson rt<<1 #define rson rt<<1|1 using namespace std; typedef long long ll; const int maxn=2e5+10; //区间查询 区间更新线段树 ll tree[maxn<<2],lazy[maxn<<2]; void pushdown(int rt,int l,int r){ lazy[lson]=(lazy[lson]+lazy[rt]); lazy[rson]=(lazy[rson]+lazy[rt]); int mid=(l+r)/2; tree[lson]=tree[lson]+lazy[rt]*(mid-l+1); tree[rson]=tree[rson]+lazy[rt]*(r-mid); lazy[rt]=0; } void pushup(int rt) { tree[rt]=(tree[lson]+tree[rson]); } int wt[maxn]; void build(int rt,int l,int

[SDOI2013]森林(树上主席树)

 ̄綄美尐妖づ 提交于 2020-02-07 10:45:21
[SDOI2013]森林(luogu) Description 题目描述 小Z有一片森林,含有N个节点,每个节点上都有一个非负整数作为权值。初始的时候,森林中有M条边。 小Z希望执行T个操作,操作有两类: Q x y k 查询点x到点y路径上所有的权值中,第k小的权值是多少。此操作保证点x和点y连通,同时这两个节点的路径上至少有k个点。 L x y 在点x和点y之间连接一条边。保证完成此操作后,仍然是一片森林。 为了体现程序的在线性,我们把输入数据进行了加密。设lastans为程序上一次输出的结果,初始的时候lastans为0。 对于一个输入的操作 Q x y k ,其真实操作为 Q x^lastans y^lastans k^lastans 。 对于一个输入的操作 L x y ,其真实操作为 L x^lastans y^lastans 。其中^运算符表示异或,等价于pascal中的xor运算符。 请写一个程序來帮助小Z完成这些操作。 对于所有的数据,n,m,T<= 8*10^4 8 ∗ 1 0 4. 输入格式 第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1<=testcase<=20。 第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。 第三行包含N个非负整数表示 N个节点上的权值。 接下来 M行,每行包含两个整数x和 y,表示初始的时候

luogu题解P4198楼房重建--线段树神操作

自古美人都是妖i 提交于 2020-02-07 07:08:14
题目链接 https://www.luogu.org/problemnew/show/P4198 分析 一句话题意,一条数轴上有若干楼房,坐标为 \(xi\) 的楼房有高度 \(hi\) ,那么它的斜率为 \(hi/xi\) ,操作包含单元素高度修改,动态询问最长上升斜率序列个数 一开始想什么分治或是离线操作之类的,却因为水平低并不会做,看了题解居然发现就是线段树!看了一下感觉真妙啊,线段树真是个神奇的数据结构 线段树维护两个东西 \(sum[now],mx[now]\) ; \(sum[now]\) 是 \(now\) 管辖区间 \([l,r]\) 的最长上升斜率个数 类似的 \(mx[now]\) 就是那个区间最大斜率,也就是最长上升序列中最右边的 我们假设更新操作递归到 \([L,R]\) 区间,设 \(p\) 为 \([L,mid]\) 区间最大斜率 \(mx[now<<1]\) 那么 \([L,R]\) 区间的贡献 \((sum[now])\) 显然等于 \([L,mid]\) 区间贡献 \((sum[now<<1])\) \(+\) 统计 \([mid+1,R]\) 区间中大于 \(p\) 的最长上升序列个数. 那么怎么计算 \([mid+1,R]\) 区间中的大于 \(p\) 的最长上升序列个数呢,这个我在代码中给出了详细的注释 代码 #include <cstdio

CF932F(李超线段树+dp)

☆樱花仙子☆ 提交于 2020-02-07 00:38:42
CF932F(李超线段树+dp) 此题又是新玩法, 李超线段树合并优化 \(dp\) 一个显然的 \(\Theta(n^2)dp\) : \(dp[x]\) 表示从x出发到叶子节点的最小代价 \(dp[x] = \min(dp[y] + a[x] * b[y]) ~~(y \in subtree(x))\) 如果我们将 \(b[y]\) 看成斜率, \(dp[y]\) 看成纵截距, \(a[x]\) 看成横坐标, 那么问题转为了在平面上有一些直线, 选出与直线 \(x = a[x]\) 相交的最靠下的点吗, 李超线段树板题, 但这道题出到了树上所以要用上线段树合并 因为有负数所以要整体右移一下, 相应的直线也需变换, 具体见代码 代码: #pragma GCC optimize(3) #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define re register #define ll long long using namespace std; template <typename T> void read(T &x) { x = 0; bool f = 0; char c = getchar(); for (;!isdigit(c);c=getchar()) if

Billboard HDU - 2795 线段树维护最大值

别说谁变了你拦得住时间么 提交于 2020-02-06 23:13:05
题目链接:https://vjudge.net/problem/HDU-2795 转自:https://blog.csdn.net/weixin_43693379/article/details/98726378 题意:有一块h*w的广告牌,现有多个广告,每个广告都是1 * x的大小,总是往最上方放置,并且如果可能就往最左放置,输出放置的行. 思路:注意到h最大1e9,但是因为一个广告最多占一行,即h如果比n大,那么h=n。在查询之前首先判断能否放置。 # include <cstdio> # include <iostream> # include <algorithm> # include <cstring> # include <cmath> # include <vector> using namespace std ; const int maxn = 8e5 + 5 ; int h , w , n ; struct node { int l , r , sum , lazy ; node ( ) { l = r = sum = lazy = 0 ; } } a [ maxn ] ; void update ( int k ) { a [ k ] . sum = max ( a [ 2 * k ] . sum , a [ 2 * k + 1 ] . sum ) ; }

题解 UVA1479 【Graph and Queries】

会有一股神秘感。 提交于 2020-02-05 11:52:44
\[ \text{Preface} \] 算是一道思维难度稍易,代码难度稍难的题吧。 \[ \text{Description} \] 给出一张 \(n\) 个点, \(m\) 条边的图,点带权。需要支持三个操作: D x 删掉编号为 \(x\) 的边 Q x k 查询与节点 \(x\) 联通的所有节点中,点权第 \(k\) 大节点的点权 C x v 将节点 \(x\) 点权改为 \(v\) 多组数据,每组数据最终需要输出所有查询的平均值 ( 保留 6 位 ) ,没有强制在线。 \[ \text{Solution} \] 不知道大家有没有做过 这道题 ,推荐先去做一下。 \(~\) 首先,对于同一个连通块里的所有节点,查询与任意一个节点连通的所有节点的第 \(k\) 大,都是查询该连通块里所有节点的第 \(k\) 大。已经很明显可以用并查集维护每个连通块的代表节点,再在这个代表节点上用一个数据结构维护连通块信息,支持合并,查询第 \(k\) 大。 我们发现权值线段树可以做到上述操作,尝试用权值线段树维护,每个节点开一个权值线段树。 \(~\) 对于操作 Q x k \(:\) ​ ​ ​ ​ 权值线段树基本操作。 对于操作 C x v \(:\) ​​ ​ ​ ​ 我们可以看作是在 \(x\) 这个位置上少了一个原来的点权,再多了一个新的点权,两次插入操作即可解决。 对于操作 D