线段树

hdu 6703 array 权值线段树

自闭症网瘾萝莉.ら 提交于 2019-11-28 10:28:54
题目读了半天没读懂...... 给你一个长度为n的排列a。两种操作,每次把里面的某个数增加 10 , 000 , 000,或者询问不等于a1-ar,且不小于k的最小的数是多少。k不超过n。 所以答案必定不超过n+1。 我们考虑对原序列做权值线段树,下标为原序列的值,值为原序列的下标。 先考虑没有修改,那么不小于k就是只从线段树下标为[k + 1,n + 1]的范围找答案。不等于a1-ar就是线段树的值(原序列下标)要大于r。要最小的数,就是能往左子树找就往左子树找。 考虑修改,某个数ai增加了 10 , 000 , 000,则意味着,原先ai这个数,再也不会被a1-ar这个条件限制了,因为a是一个排列,ai独此一份,现在被改成了个很大的数。所以干脆把线段树下标ai对应的值改成n+1,这样子,就再也不会受a1-ar这个条件限制了。 复杂度是mlogn,直观感受下就是,不再范围内的部分,发现出界会立马停止。在范围内的部分,只有一条会递归到底,一共两条,所是logn。 1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <cmath> 5 using namespace std; 6 const int MAXN = 101000; 7 int n,m,T,vec[MAXN],a[MAXN]

权值线段树模板题

守給你的承諾、 提交于 2019-11-28 10:17:20
array Time Limit: 1500ms Memory Limit: 256M Description You are given an array . Initially, each element of the array is unique. Moreover, there are instructions. Each instruction is in one of the following two formats: 1. ,indicating to change the value of to ; 2. ,indicating to ask the minimum value which is not equal to any ( ) and not less than . Please print all results of the instructions in format . Input The first line of the input contains an integer , denoting the number of test cases. In each test case, there are two integers , in the first line, denoting the size of array and the

模板 - 线段树

 ̄綄美尐妖づ 提交于 2019-11-28 10:01:28
线段树还需要模板的菜鸡 #include<bits/stdc++.h> using namespace std; typedef long long ll; #define lt ls, l, m #define rt rs, m + 1, r #define ls (o<<1) #define rs (o<<1|1) const int MAXM = 100000 + 5; ll a[MAXM]; ll st[MAXM * 4], lazy[MAXM * 4]; inline void PushUp(int o) { st[o] = st[ls] + st[rs]; } inline void PushDown(int o, int l, int r) { if(lazy[o]) { lazy[ls] += lazy[o]; lazy[rs] += lazy[o]; int m = l + r >> 1; st[ls] += lazy[o] * (m - l + 1); st[rs] += lazy[o] * (r - m); lazy[o] = 0; } } void Build(int o, int l, int r) { if(l == r) st[o] = a[l]; else { int m = l + r >> 1; Build(lt); Build(rt);

线段树(模板

放肆的年华 提交于 2019-11-28 09:43:35
某大佬的模板#include <iostream> #include <cstdio> typedef long long LL; LL n, a[100005], d[270000], b[270000]; void build(LL l, LL r, LL p) {//建树 if (l == r) { d[p] = a[l]; return; } LL m = (l + r) >> 1; build(l, m, p << 1), build(m + 1, r, (p << 1) | 1); d[p] = d[p << 1] + d[(p << 1) | 1]; } void update(LL l, LL r, LL c, LL s, LL t, LL p) {//区间加数 if (l <= s && t <= r) { d[p] += (t - s + 1) * c, b[p] += c; return; } LL m = (s + t) >> 1; if (b[p]) d[p << 1] += b[p] * (m - s + 1), d[(p << 1) | 1] += b[p] * (t - m), b[p << 1] += b[p], b[(p << 1) | 1] += b[p]; b[p] = 0; if (l <= m) update(l, r, c, s, m,

树套树-线段树套平衡树

感情迁移 提交于 2019-11-28 08:56:37
树套树留坑 线段树套平衡树: 二逼平衡树 #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);

[笔记] 线段树的兄弟姐妹们

核能气质少年 提交于 2019-11-28 08:20:24
0.树状数组 常数极小,只能做前缀和,不过可以通过一些技巧让它做很多事情 比如,支持区间修改,区间查询: #include<algorithm> #include<iostream> #include<cstdio> using namespace std; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } const int MAXN = 100005; typedef long long ll; int n,m; int t1[MAXN],t2[MAXN]; int querys(int x){ int ret=0; for(int i=x;i;i-=i&-i)ret+=(x+1)*t1[i]-t2[i]; return ret; } int query(int l,int r){ return querys(r)-querys(l-1); } void updates(int x,int w){ for(int i=x;i<=n;i+=i&-i)t1[i]+=w,t2[i]+=x*w; } void update(int l,int r

【学习笔记】扫描线

做~自己de王妃 提交于 2019-11-28 08:16:24
一.关于扫描线   基础是求周长并和面积并的算法。   注意,扫描线是一条不存在的线。   假设有一条扫描线从一个图形的下方扫向上方(或者左方扫到右方),那么通过分析扫描线被图形截得的线段就能获得所要的结果。 二.扫描线求面积并(由于本人不会做图,以下图片均来自洛谷的题解)   我们看一下这个东西。      我们模拟一条扫描线,从下到上扫过整个平面。   这条扫描线会在遇到横向线段的时候停下来更新一些东西。那么整个图形就可以找出四条线段。   如图:   我们要更新什么呢?当然是计算线段的长度了。   所以我们要记录的第一种东西就确定了。是每条线段的左右端点坐标。   然后我们把这些坐标放到一个数组,就叫X[]吧。   这个东西是需要排序的。具体原因请往下看。   那么我们考虑,在扫描线单调向上的过程中,怎么知道哪里有面积,哪里是空的呢?   我们想到一个矩形有上底和下底,在扫描线单调向上的过程中,总是先遇到一个矩形的下底,再遇到上底,然后这个图形的面积就被扫描线扫过了。   所以我们要记录第二个东西,给每条横向线段赋上一个权值,如果是下底则赋为1,如果是下底则赋为-1,这样扫描线扫有权值的部分就有我们要计算的面积。   然后我们考虑面积并的问题,我们知道,两个矩形相交的部分只能计算一次面积。   两个矩形相交,一个矩形的横向边上至少有1个另一个矩形边上的点。   那么如上图X

POJ3667 Hotel 线段树

北战南征 提交于 2019-11-28 06:20:55
题意:一个旅馆有很多房间,要安排客人住宿。有如下要求: 1、房间排列是线性的(即呈一条线)。 2、每个房间只能住一个人。 3、每来一个团队住宿,只能安排在连续的编号里,且若有多种情况满足条件,开始位置必须尽可能早。 4、若不能住下当前团队,输出0,否则输出起始编号。 思路:拿到这个题目还是毫无思路,不过还好是模板题,就用学长发的模板套了一下。 1、首先建树,我们需要维护三个变量,lmax,rmax,mmax,分别代表从当前区间左侧开始、右侧开始和中间部分最大空余位置数量。为了便于统计剩余数量,我们把房间情况初始化为1 代表有1个空屋。 2、其次更新信息(即客人入住)。因为是区间修改,且数据量不小,所以我们需要lazy标记来延迟更新以减小时间复杂度。 3、最后query函数的作用是用来查询 最早满足条件的起点位置 。既然最早,所以要从左边开始找合适的嘛,所以是左中右的搜索方式。 另外从代码中可以注意到 只有搜索中间子树的时候是返回的确定值,否则都是返回的调用某个函数。这里很有意思,也是关键代码,可以细细琢磨一下,如下: if ( t [ k << 1 ] . mmax >= len ) return query ( k << 1 , len ) ; //注意这里。。搞清关系!若左子右边界就得加一 不然不用 else if ( t [ k << 1 ] . rmax + t [ k <

【树套树】【XSY1952】【BZOJ3295】动态逆序对

≯℡__Kan透↙ 提交于 2019-11-28 06:16:56
\(Description\) 对于序列 \(A\) ,它的逆序对数定义为满足 \(i<j\) ,且 \(A_{i}\) > \(A_{j}\) 的数对 \((i,j)\) 的个数。给 \(1\) 到 \(n\) 的一个排列,按照某种顺序依次删除 \(m\) 个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。 \(Input\) 输入第一行包含两个整数 \(n\) 和 \(m\) ,即初始元素的个数和删除的元素个数。以下 \(n\) 行每行包含一个 \(1\) 到 \(n\) 之间的正整数,即初始排列。以下 \(m\) 行每行一个正整数,依次为每次删除的元素。 \(Output\) 输出包含 \(m\) 行,依次为删除每个元素之前,逆序对的个数。 \(Sample Input\) 5 4 1 5 3 4 2 5 1 4 2 \(Sample Output\) 5 2 2 1 \(HINT\) 样例解释 \((1,5,3,4,2)⇒(1,3,4,2)⇒(3,4,2)⇒(3,2)⇒(3)。\) \(M≤N≤100000\) 思路 我们第一眼看上去,哇,三维偏序 再看一眼,哇,待修三维偏序 于是我们选择用树套树实现 在这里我们选择树状数组套权值线段树 但是我们发现,如果直接开点可能会爆空间?! 那就动态开点线段树咯 我们在树状数组每个节点开一棵线段树

HDOJ-6681(离散化+线段树)

夙愿已清 提交于 2019-11-28 06:12:38
Rikka With Cake HDOJ-6681 最终的答案为射线的交点数加一。当然,我们也可以证明。证明需要用到欧拉公式 V−E+F=2 V-E+F=2V−E+F=2 。设射线的交点共 c cc 个。则在这个图中,V=K+4+K+c=2K+c+4 V=K+4+K+c=2K+c+4V=K+4+K+c=2K+c+4 , E=2∑(ci+1)+K+4=2K+2c+4 E=2\sum (c_i+1)+K+4=2K+2c+4E=2∑(ci+1)+K+4=2K+2c+4 。因此 F=2−V+E=c+2 F=2-V+E=c+2F=2−V+E=c+2 。减去外面的无穷区域,得出答案为 c+1 c+1c+1 。 原文链接: https://blog.csdn.net/qq_43549984/article/details/99762559 首先需要先按y的值进行从小到大排序。 再对y进行离散化,所谓离散化就是将y排序后的点放在一个数组中,用点在数组中的序号代替y,达到缩小范围的作用。 其次再根据x从小到大排序,因为要根据x开始遍历。首先从左到右遍历方向指向左的点,计算交点。如果是上下方向的则update线段树记录每个点的y覆盖的线段的长度。再从右到左遍历。 #include<iostream> #include<cstdio> #include<cstring> #include<string>