线段树

HDU - 3577 Fast Arrangement 线段树

匿名 (未验证) 提交于 2019-12-03 00:18:01
Fast Arrangement Problem Description Chinese always have the railway tickets problem because of its' huge amount of passangers and stations. Now goverment need you to develop a new tickets query system. One train can just take k passangers. And each passanger can just buy one ticket from station a to station b. Each train cannot take more passangers any time. The one who buy the ticket earlier which can be sold will always get the ticket. Input The input contains servel test cases. The first line is the case number. In each test case: The first line contains just one number k( 1 ≤ k ≤ 1000 )

线段树(一)之点修改

匿名 (未验证) 提交于 2019-12-03 00:18:01
首先,明确一点,线段树并不是什么神奇的东西,只是巧妙地利用了分治的思想,它用于区间的动态查询问题~ 线段树由很多下面这样的单元组合起来的(我懒地画图了),其中M=L+(R-L)/2(当然也可以写成(L+R)/2,但我们应该养成用前面那种方式找中值的习惯,当L和R特别大的时候,L+R有可能 溢出 ,不过线段树上一般没什么问题),使用线段树的前提是你求的东西必须满足区间加法 顺便提一下: 如果知道了[l, m] ,[m + 1, r]的信息 就可以知道[l, r]的信息 这个就叫做满足区间加法,也就是上图的【L,M】 + 【M+1,R】 = 【L,R】 如果知道了[1, r] ,[1, l - 1]的信息 就可以知道[l, r]的信息 这个就叫做满足区间减法,也就是上图的【L,R】 - 【L,M】 = 【M+1, R】 举个栗子,你要求最小值,用min(a, b)表示【a, b】区间最小值,那么:min(L,R)=min( min(L,M), min(M+1, R) )――这很好理解的吧~ 同样,还有区间最大值,区间和等等~ 差不多意思明白了,现在是具体实现问题了,给一个数组a[],数组大小为n,那么如何建树? 首先,一般也使用数组来存储线段树,设为segTree[ ]吧,即: 也就是满足: 方框里的值对应的是是线段树数组的索引,也就是标号,值得注意的是

【数据结构】――线段树板子

匿名 (未验证) 提交于 2019-12-03 00:17:01
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 int read(){ 5 int x=0,f=1; 6 char c=getchar(); 7 while(!isdigit(c)){ 8 if(c=='-') f=-1; 9 c=getchar(); 10 } 11 while(isdigit(c)){ 12 x=(x<<1)+(x<<3)+(c^48); 13 c=getchar(); 14 } 15 return x*f; 16 } 17 const int N=1e5+10; 18 int n,m,p; 19 int a[N]; 20 struct tree{ 21 ll sum[N<<2]; 22 ll add[N<<2],mul[N<<2]; 23 int ls(int o){return o<<1;} 24 int rs(int o){return o<<1|1;} 25 void pushup(int o){ 26 sum[o]=(sum[ls(o)]+sum[rs(o)])%p; 27 } 28 void pushdown(int o,int l,int r){ 29 int mid=(l+r)>>1; 30 sum[ls(o)]=(sum[ls(o)]*mul

【NOIP2019模拟11.01】Game(贪心+线段树)

匿名 (未验证) 提交于 2019-12-03 00:17:01
Description: \(1<=n<=10^5\) 考虑求最高的得分。 每个人肯定希望打比他低的又最高的。 所以排个序,扫一遍即可,正着扫倒着扫好像都可以。 现在要字典序最大,考虑逐位确定。 发现每一位可以二分,那么要支持删除的情况下动态维护最高得分。 显然可以线段树,要维护三个标记,已经匹配的,a剩下多少,b剩下多少。 直接搞就是 \(O(n~log^2n)\) 。 考虑线段树多维护一个东西表示在这个区间删掉最左的之后的三个标记。 那就可以在线段树上面二分了,复杂度: \(O(n~log~n)\) 。 Code: #include<bits/stdc++.h> #define fo(i, x, y) for(int i = x, B = y; i <= B; i ++) #define ff(i, x, y) for(int i = x, B = y; i < B; i ++) #define fd(i, x, y) for(int i = x, B = y; i >= B; i --) #define ll long long #define pp printf #define hh pp("\n") using namespace std; const int N = 1e5 + 5; int n; int a[N], b[N]; const int inf = 1e9;

总结-李超线段树

匿名 (未验证) 提交于 2019-12-03 00:14:01
李超线段树可用来维护直线关系,支持: 加入一条直线 询问单点对应最优直线 结构与普通线段树类似,但更多分情况讨论 模板 #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <cmath> #define R ( a , b , c ) for ( register int a = ( b ); ( a ) <= ( c ); ++( a )) #define nR ( a , b , c ) for ( register int a = ( b ); ( a ) >= ( c ); --( a )) #define Fill ( a , b ) memset ( a , b , sizeof ( a )) #define Swap ( a , b ) (( a ) ^= ( b ) ^= ( a ) ^= ( b )) #define ll long long #define u32 unsigned int #define u64 unsigned long long #define ON_DEBUGG #ifdef ON_DEBUGG #define D_e_Line printf ( "\n----------\n" ) #define D_e ( x )

可持久化线段树,可持久化权值线段树(主席树)

匿名 (未验证) 提交于 2019-12-03 00:13:02
1 struct node 2 { 3 int lc,rc; 4 int sum; 5 node() 6 { 7 lc=rc=sum=0; 8 } 9 }; 10 node tree[maxn*5]; 11 inline int build(int l,int r) 12 { 13 int k=++cnt; 14 if(l==r) 15 { 16 tree[k].sum=num[l]; 17 return k; 18 } 19 int mid=(l+r)>>1; 20 tree[k].lc=build(l,mid); tree[k].rc=build(mid+1,r); 21 tree[k].sum=tree[tree[k].lc].sum+tree[tree[k].rc].sum; 22 return k; 23 } 1 inline int modify(int rt,int l,int r,int p,int v) 2 { 3 int new_rt=++cnt; 4 tree[cnt]=tree[rt];//先把原信息复制上,再修改即可实现 5 if(l==r) 6 { 7 tree[new_rt].sum+=v; 8 return new_rt; 9 } 10 int mid=(l+r)>>1; 11 if(p<=mid) tree[new_rt].lc=modify

线段树学习笔记(初级:只支持区间加、区间求和)

匿名 (未验证) 提交于 2019-12-03 00:12:02
研究了很长时间线段树的理论,发现打过一遍代码就啥都懂了 简单来说,线段树是基于分治对区间进行快速修改的,所以时间效率很高 然后就是代码(洛谷太坑,query里面的ans也要开long long) 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 typedef long long ll; 7 const int N = 1e5 + 5; 8 ll addv[N*4],sumv[N*4],a[N]; 9 int n,m; 10 inline int read() 11 { 12 int x=0,w=1; char c=getchar(); 13 while (c>'9'|| c<'0') {if(c=='-') w=-1; c=getchar();} 14 while (c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar(); } 15 return w*x; 16 } 17 void pushup(int k) 18 { 19 sumv[k]=sumv[k<<1]+sumv[k<<1|1]; 20 } 21 inline void build(int o,int l

【HDU5566】Clarke and room(AC自动机)(树链剖分)(线段树)

匿名 (未验证) 提交于 2019-12-03 00:11:01
传送门 题解: 在线也好离线也好,反正AC自动机只建在有询问的线段树节点上就行了。 由于树链剖分形态的特殊性,可能很多线段树节点上都没有询问(是两条链标号的并),建出来就是浪费时间。 代码: # include < bits / stdc ++. h > # define ll long long # define re register # define gc get_char # define cs const namespace IO { inline char get_char ( ) { static cs int Rlen = 1 << 22 | 1 ; static char buf [ Rlen ] , * p1 , * p2 ; return ( p1 == p2 ) && ( p2 = ( p1 = buf ) + fread ( buf , 1 , Rlen , stdin ) , p1 == p2 ) ? EOF : * p1 ++ ; } inline int get_s ( char * s ) { int len = 0 ; char c ; while ( isspace ( c = gc ( ) ) ) ; while ( s [ len ++ ] = c , ! isspace ( c = gc ( ) ) && c != EOF ) ; s [

【校内模拟】lis(线段树)(暴力)

匿名 (未验证) 提交于 2019-12-03 00:11:01
讲个笑话,数据结构压轴题96行写完。 由于没有标算,我也不知道出题人的实现写了多长。。。 题解: 按照下发的题解模拟即可 我记得区间的LIS是不能直接做的,如果能的话,这道题就没什么难度了。。。 但是这道题有两个限制:新加入的 h ≤ 10 h\leq 10 h ≤ 1 0 ,删除的数的位置 ≤ 10 \leq 10 ≤ 1 0 也就是说,随着树木的增长,比当前加入的 h h h 小的最多只有 10 10 1 0 个。 这启示我们使用暴力。 设 f i f_i f i 表示以 i i i 开头的LIS长度。 考虑怎么更新,显然需要满足两个条件,在 i i i 后面,且比 i i i 高。 对于插入,由于高度比当前小的只有不超过 10 10 1 0 个,直接开一个数据结构以位置为下标维护答案,每次暴力将这十个删除再一个个插回去。 对于删除,由于位置在当前这个之前的只有不超过 10 10 1 0 个,直接开一个数据结构以高度为下标维护答案,每次暴力将这十个删除再一个个插回去。 发现我们对于数据结构的操作是单点修改,区间询问max,上ZKW线段树。 代码: # include <bits/stdc++.h> # define ll long long # define re register # define gc get_char # define cs const namespace

[CSP-S模拟测试]:F(DP+线段树)

匿名 (未验证) 提交于 2019-12-03 00:11:01
题目传送门(内部题49) 输入格式 第一行四个整数$n,q,a,b$。 接下来$n$行每行一个整数$p_i$。 输出格式 一行一个整数表示答案。 样例 样例输入: 10 3 3 7 4 2 8 样例输出: 4 数据范围与提示 对于$30\%$的数据:$n,q\leqslant 2,000$ 对于所有数据: $1\leqslant n,q\leqslant {10}^5$ $1\leqslant p_i\leqslant n$ 题解 首先,我们考虑$30\%$的算法怎么办? 考虑$DP$,定义$dp[i][j]$表示到了第$i$步,一个指针在$p_i$,另一个指针在$j$的最短步数。 那么我们可以里出状态转移方程:   $\alpha.dp[i][j]=dp[i-1][j]+|p_i-p_{i-1}|$(上一次和这一次移动的是一个指针)   $\beta.dp[i][p_{i-1}]=dp[i-1][j]+|p_i-j|$(上一次和这一次移动的不是一个指针) 那么我们接着考虑如何优化。 发现转移$\alpha$其实就是将整个区间都加了$|p_i-p_{i-1}|$,而转移$\beta$我们可以维护$dp[i][j]+j$和$dp[i][j]-j$的最小值即可。 所以考虑线段树优化,即可得到满分。 时间复杂度:$\Theta(n\log n)$。 期望得分:$100$分。 实际得分: