线段树

hdu 6703 array(权值线段树)

匿名 (未验证) 提交于 2019-12-02 23:55:01
Problem Description a 1 , a 2 , . . . , a n ( i ∈ [ 1 , n ] , 1 ≤ a i ≤ n ) . Initially, each element of the array is **unique**. m Each instruction is in one of the following two formats: ( 1 , p o s ) a p o s a p o s + 10 , 000 , 000 ; ( 2 , r , k ) a i 1 ≤ i ≤ r k . 2 . Input T ( 1 ≤ T ≤ 10 ) , denoting the number of test cases. n ( 1 ≤ n ≤ 100 , 000 ) , m ( 1 ≤ m ≤ 100 , 000 ) a n a 1 , a 2 , . . . , a n ( i ∈ [ 1 , n ] , 1 ≤ a i ≤ n ) ,denoting the array. m ( 1 , t 1 ) ( 2 , t 2 , t 3 ) . The parameters of each instruction are generated by such way : 1 p o s = t 1 L a s t A n s 1 ≤ p o s

树套树-线段树套平衡树

匿名 (未验证) 提交于 2019-12-02 23:55:01
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> #include<cmath> #include<map> #include<bitset> #pragma GCC optimize(2) #define rep(i,a,b) for(int i=(a);i<=(b);++i) #define dwn(i,a,b) for(int i=(a);i>=(b);--i) using namespace std; typedef long long ll; const int N=6000000,inf=2147483647; int n,m,maxn,a[N+10]; int tot,rt[N+10],sz[N+10],rec[N+10],v[N+10],fa[N+10],ch[N+10][2]; inline int read() { int 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<<3)+(x<<1)+(ch^48); ch=getchar(); }

线段树基础知识详解

匿名 (未验证) 提交于 2019-12-02 23:52:01
INTRODUCTION: 线段树是一种 二叉搜索树 ,与 区间树 相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。 使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的 空间复杂度 为2N, 实际应用时一般还要开4N的数组以免越界,因此有时需要离散化让空间压缩。--百度百科 首先来看一类题: 洛谷P3372 给定一个有100000个元素的数组,并给出10000个操作,操作分为两种: 1.将数组中的第 l 个到第 r 个元素全部加上 k 2.输出第 l 元素到第 r 个元素的总和 对于这类对区间进行修改与查询的题,数据范围往往极大,所以暴力往往是不可行的,因此就要用到线段树这种高效的区间修改与查询数据结构了 那么线段树有什么优势呢? 1.动态:相对其他只支持查询的数据结构,线段树不但支持查询,还支持修改(单点修改与区间修改),并且这两种操作的时间复杂度都相当低 2.全能:线段树同时支持区间查询与区间修改,单点查询与单点修改,不但可以维护区间内所有元素的和,还可以维护区间最大值等等可以代替     多种其他数据结构,当然时间复杂度可能会稍大一些 3.快速:线段树继承了树形数据结构的优势,无论是查询还是修改,时间复杂度都是 O(logn) 那么接下来以支持区间查询与区间修改

任务清单

匿名 (未验证) 提交于 2019-12-02 23:52:01
最近囤积的任务有点多脑子记不过来了 BSGS 群论、线性基 excrt NOIP模拟测试9的T1 NOIP模拟测试10的T2 动态开点线段树,主席树 线段树启发式合并,平衡树启发式合并,树上启发式合并 高斯消元

[BZOJ3064][Tyvj1518] CPU监控

匿名 (未验证) 提交于 2019-12-02 23:52:01
思路: 线段树专题讲的。以下为讲课时的课件: 给出序列,要求查询一些区间的最大值、历史最大值,支持区间加、区间修改。序列长度和操作数<=1e5。 维护标记的线段树裸题。出这道题的目的就是为了让大家加强对于线段树标记下传的理解,以及线段树维护信息时分类讨论一定要明确。 在确定了要写线段树后,先考虑要维护哪些标记。然后思考这些标记应当如何维护,何时下传,何时修改。特别注意,当区间加、区间覆盖操作同时存在时,标记之间的先后处理顺序非常重要。 这道题细节非常多,难点集中于标记下传。 具体做法:对于既有set又有add的线段树,在任何时刻,同一个节点上必然不能同时出现set和add两种标记,因为set和add会由顺序不同导致冲突。 接着,先不管查询历史操作,只考虑标记的合并与传递。既然两种标记不能并存,那在传递的时候一定要讨论当前节点和子节点的标记情况,分情况传递。 这样,每次访问到一个非叶子节点时,首先进行标记下传更新子节点信息,清空当前节点标记,而每次修改时,如果区间被完全包含,则直接给节点打上标记,更新当前节点信息即可。 最后来考虑历史信息的维护。我们需要在进行操作时,不遗漏没有进行操作的节点出现的最大值,所以维护了“从上次pushdown该节点直到现在,区间中出现的最大set与add标记”,这样,区间的历史最值(答案、set、add

[ZJOI2019]Minmax搜索

匿名 (未验证) 提交于 2019-12-02 23:52:01
Solution 叶子节点的变化区间是连续的,可得知非叶子节点的权值变化区间也是连续的 由此可知, \(W\) 的变化值的可行域也是连续的,所以只需要看它能否变为 \(W+1\) 或 \(W-1\) 对于答案,可以先求消耗能量不超过 \(k\) 的集合数 \(ans_k\) ,再进行查分 发现 \(ans_1=2^{m-1},ans_n=2^{m}-1\) 首先发现,如果要将 \(W\) 的值 \(+1\) ,那么只会去动那些 \(\leq W\) 的的节点,让它们的权值变大 类似的,我们发现处理的两类节点无交,所以可以分别求出可以使得 \(W\) 加一或者减一的概率 因为通过减少较大权值的点的权值的办法都可以被上面的方法取代 当且仅当包含了 \(W\) 点,只需要耗费 \(1\) 的能量 接下来考虑不包含 \(W\) 点的情况,假如我们要求 \(ans_k\) 把 \(<W\) 的节点称作小节点, \(>W\) 的节点称作大结点 设 \(f_i\) 表示只改动小节点的值但是 \(i\) 点权值仍然 \(\leq W\) 的概率 奇数点: \[ f_u=\prod f_v \] 偶数点: \[ f_u=1-\prod(1-f_v) \] 设 \(g_i\) 表示可以通过改变大结点来使得 \(i\) 点权值 \(<W\) 的概率,转移与 \(f_i\) 相似 所以,得到 \[ ans

HDU - 5306 Gorgeous Sequence 线段树 + 均摊分析

匿名 (未验证) 提交于 2019-12-02 23:49:02
#include<algorithm> #include<cstdio> #include<cstring> #define ll long long #define setIO(s) freopen(s".in","r",stdin) #define maxn 2000000 #define lson (now<<1) #define rson ((now<<1)|1) using namespace std; int n,q; ll arr[maxn],mx[maxn<<2],se[maxn<<2],cnt[maxn<<2],sum[maxn<<2]; void pushup(int l,int r,int now) { int mid=(l+r)>>1; int ls=lson,rs=(r>mid)?rson:0; sum[now]=sum[ls]+sum[rs]; if(mx[ls]>mx[rs]) mx[now]=mx[ls],cnt[now]=cnt[ls],se[now]=max(se[ls],mx[rs]); if(mx[rs]>mx[ls]) mx[now]=mx[rs],cnt[now]=cnt[rs],se[now]=max(se[rs],mx[ls]); if(mx[ls]==mx[rs]) mx[now]=mx[ls],cnt[now]=cnt[ls]

线段树(区间覆盖+区间加法)

匿名 (未验证) 提交于 2019-12-02 23:49:02
#include<iostream> #include<cstdio> #include<cctype> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> #include<ctime> #define ls (o<<1) #define rs (o<<1|1) using namespace std; const int N =1e6+5; inline int read(){ char x =getchar(); int a =0; while(!isdigit(x)) x =getchar(); while(isdigit(x)) a =a*10+x-48,x =getchar(); return a; } int val[N<<2],add[N<<2],set[N<<2],n; inline void update(int o){ val[o] =max(val[ls],val[rs]); } inline void down(int o){ if(set[o]!=-1){ val[ls] = val[rs] =set[o]; set[ls] = set[rs] =set[o]; add[ls] = add[rs] =0; set[o] =-1; } else if(add[o])

线段树优化dp(elect选择)

匿名 (未验证) 提交于 2019-12-02 23:49:02
好几天以前的考试题,现在才想起来调。。 题意 暴力:O(n*m*m*T) 优化 :对于将要选的一行格子,将其上一行格子能够覆盖的范围处理出来,然后选这一行时,希望较快的得到在这个格子可以选的范围里面,权值最小的一格 于是对每一行用线段树维护最小值,到了下一行就把线段树清空,重新modify #include<bits/stdc++.h> using namespace std; #define mid ((l+r)>>1) #define N 105 #define M 5005 #define inf 0x7f7f7f int a[N][M],dp[N][M],minn[M*4],fl[M*4],l[N][M],r[N][M]; void update(int s) { minn[s]=min(minn[s<<1],minn[s<<1|1]); } void pushdown(int s) { if(fl[s]==inf) return ; minn[s<<1]=min(minn[s<<1],fl[s]); fl[s<<1]=min(fl[s<<1],fl[s]); minn[s<<1|1]=min(minn[s<<1|1],fl[s]); fl[s<<1|1]=min(fl[s<<1|1],fl[s]); fl[s]=inf; } void build(int s,int l

线段树入门

匿名 (未验证) 提交于 2019-12-02 23:49:02
1.我想单点查询序列的值,怎么办? 当然是来一个数组啦! 2.我想单点查询序列的值,还想单点修改,怎么办? 还是数组! 3.我想区间求和(后文称为查询),怎么办? 维护一个前缀和, \(sum[i]=\sum_{j=1}^ia[i]\) 就可以 \(O(1)\) 查询。 4.我想区间求和,还想单点修改,怎么办? 退役吧 。。 如果你至今还抱着万物皆可 \(O(1)\) 的幻想,那就 \(Too\,young\,too\,simple\) 了。 我来帮你复习一下: 1.OI \(\to\) 计算机 \(\to\) 二进制 \(\to O(log_2n)\) 2. \(OI \to \text{(幻视)} 01\to \text{二进制}\) \(\to\) \(O(log_2n)\) “二进制”思想在算法中应用广泛,从二分到倍增等,都化 \(n\) Ϊ \(log_2n\) ,避免了被卡飞的惨剧。所以就有了神奇的树状数组。 【注:你说差分?太强了,没听说过。】 5.现在毒瘤出题人要求你区间查询,区间修改。这类问题可以用线段树来解决。 听说你树状数组很6,甚至还会差分?? 【注:图片来自百度百科,但是看上去百度百科也是侵权的w我就不删了】 图中的巨型树状物就是一颗线段树。也就是说,将一个大区间取中点得到小区间,组成一颗二叉树,这就叫线段树。 这和树状数组大同小异。将大区间拆成至多 \