线段树

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

寵の児 提交于 2019-11-30 17:05:43
研究了很长时间线段树的理论,发现打过一遍代码就啥都懂了 简单来说,线段树是基于分治对区间进行快速修改的,所以时间效率很高 然后就是代码(洛谷太坑,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

权值线段树板子题

放肆的年华 提交于 2019-11-30 16:55:34
https://www.luogu.org/problem/P1168 #include <bits/stdc++.h> using namespace std; const int maxn=1e5+5; int tree[maxn*4]; int dtc[maxn]; int a[maxn]; void pushup(int root) { tree[root]=tree[root<<1]+tree[root<<1|1]; } void update(int root,int l,int r,int index) // 将权值线段树上值为index(已离散化)的位置值+1 { if(l==r) { tree[root]++; return; } int mid=(l+r)/2; if(mid>=index) update(root<<1,l,mid,index); else update(root<<1|1,mid+1,r,index); pushup(root); } int querry(int root,int l,int r,int k) // 查询第k大的数字 { if(l==r) return l; int mid=(l+r)/2; if(tree[root<<1]>=k) return querry(root<<1,l,mid,k); return querry

浅谈线段树分治

蹲街弑〆低调 提交于 2019-11-30 16:47:23
线段树分治 首先我们要理解线段树(现在指狭义的线段树)是什么。 线段树是一种容易维护区间的数据结构,是一种区间分治实体化的产物。 准确来说,比如你维护区间 [L,R], 其实就可以不断以中点分治下去。 由于每次分治区间长度都会除以 2 ,所以最多分治 log层,就形成了线段树。 那么线段树分治指什么呢? 实际上是一种 维护时间区间 的数据结构,同样是利用线段树的分治性,让复杂度保证在了 log级别。 但是,维护时间区间的东西还有很多, 比如 CDQ 分治 , KD-Tree ,这一类数据结构都能 维护时间区间 , 那线段树分治的 特殊作用 在哪里呢? 实际上,一般而言,它的作用就是支持 撤销 操作,或者说就是维护了一个操作影响的时间区间. 例题: 题目大意 有一幅图,n个点,m条边,边有边权。 有三种操作:加边,删边,询问把图划分为两个点 集后两个端点属于同一个点集的边的最大值的最小值。 solution : 每次询问将当前存在的边排序后,从大到小依次加入,若加入一条边后出现 奇环 ,则这条边就是答案 可以发现, 那些加进去只产生偶环的边是没有用的 。 因此只 有O(n)条边是有用的(即不产生环的边和第一次产生奇环的边)。 考虑 线段树分治 ,把每条边按其存在时间的区间加入到线段树中。 对线段树每个节点,会 有许多条边。 预处理出每个节点上有用的O(n)条边。 然后每次询问就是把O

POJ2528Mayor's posters 线段树,离散化技巧

一笑奈何 提交于 2019-11-30 16:27:42
题意:一个坐标轴从1~1e7,每次覆盖一个区间(li,ri),问最后可见区间有多少个(没有被其他区间挡住的) 线段树,按倒序考虑,贴上的地方记为1,每次看(li,ri)这个区间是否全是1,全是1就说明在它后面贴的把它给挡住了,否则该海报可见。 然后就愉快的MLE了。。。。 再看看数据范围,离散化如下,比如如果海报的左右端点如下 那图中橙色的一块的大小其实对结果没有影响,可以把他们都缩为1 最后离散化结果如下图: 代码: 1 #include <algorithm> 2 #include <iostream> 3 #include <cstdio> 4 #define nmax 10010 5 #define tn t[node] 6 #define sl (node<<1) 7 #define sr (1+(node<<1)) 8 9 using namespace std; 10 int n; 11 int inl[nmax],inr[nmax]; 12 struct tin{ 13 int pd,id,num,n2; //0 ->l 1->r 14 bool operator < (const tin x) const { return x.num>num; } 15 }in[nmax*2]; 16 struct segt { int l,r,v; }t[nmax*15];

线段树合并总结

孤街浪徒 提交于 2019-11-30 16:10:23
线段树合并总结 咕咕咕 原理 复杂度 两棵线段树合并复杂度即为两棵树公共节点数 \(\times logn\) ,据说因为实际重合部分一般比较少,一次合并两棵线段树的复杂度近似为 \(O(logn)\) ,所以合并 \(n\) 棵线段树复杂的为 \(O(nlog_n)\) 。 题 CF600E Lomsat gelral 一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和。 权值线段树,下标为颜色,维护区间答案和最多颜色编号和,然后自底向上合并即可。 #include <cstdio> #define MAXN 100010 #define sl tre[x].l #define sr tre[x].r #define ll long long using namespace std; int head[MAXN],vv[MAXN*2],nxt[MAXN*2],tot; inline void add_edge(int u, int v){ vv[++tot]=v; nxt[tot]=head[u]; head[u]=tot; } struct nod{ int l, r; ll ans, sum; }tre[MAXN*2*20]; int rt[MAXN],cnt,n; int col[MAXN]; ll res[MAXN]; void

cf 1216f

一笑奈何 提交于 2019-11-30 15:18:33
https://codeforc.es/problemset/problem/1216/F 有直线上n个位置,每个位置上可以花费i的代价使得联网,某些位置可以放置路由器,放路由器的代价也是i,放置了路由器以后,可以让[i-k,i+k]的范围内上网,要求每台电脑都可以上网,最少需要多少代价。 思路: 动态规划+贪心+线段树维护 f[i]表示前i个电脑上网所需要的最小费用。 转移的时候分为两种情况。 1. 第i台电脑独立上网,花费的代价是i f[i-1]+i 2 第i台电脑通过前面某台电脑的路由器上网,根据贪心的原则,肯定是在[i-k,i-1]里面位置最小的可以放路由器的地方,一来覆盖的范围可以更大,二来费用更低。 我们可以通过线段树里面维护这个位置,二分来查找。 转移的时候,注意由于区间可以重叠,所以我们要求一个区间最小值来进行转移,还是用线段树来做。 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define LL long long 4 #define lc (x<<1) 5 #define rc (x<<1|1) 6 #define mid (l+r)/2 7 int const N=200000+10; 8 char s[N]; 9 LL f[N],v[N<<2]; 10 int n,k,sum[N<<2],pos[N

需要补的题

瘦欲@ 提交于 2019-11-30 13:22:39
字符串 [ ] Rikka with Stable Marriage-字典树 [ ] trie [ ] ac自动机 [ ] 字符串 [ ] SAM [ ] SAM [ ] SAM 树 [ ] Rikka with Travels-树的直径 [ ] 直径 [ ] 直径 数据结构 [x] 动态开点 [ ] 线段树 [ ] 线段树 [ ] 线段树 [ ] 线段树 [ ] hdu6240 数学 [ ] 高等数学 图论 [ ] 2-sat [ ] 网络流 来源: https://www.cnblogs.com/C-W-K/p/11592685.html

P1890 gcd区间 线段树

馋奶兔 提交于 2019-11-30 11:58:04
题目描述 给定一行 \(n\) 个正整数 \(a[1]..a[n]\) 。 \(m\) 次询问,每次询问给定一个区间 \([L,R]\) ,输出 \(a[L]..a[R]\) 的最大公因数。 输入格式 第一行两个整数 \(n,m\) 。 第二行n个整数表示 \(a[1]..a[n]\) 。 以下 \(m\) 行,每行 \(2\) 个整数表示询问区间的左右端点。 保证输入数据合法。 输出格式 共m行,每行表示一个询问的答案。 输入输出样例 输入 #1 5 3 4 12 3 6 7 1 3 2 3 5 5 输出 #1 1 3 7 说明/提示 对于30%的数据, \(n <= 100, m <= 10\) 对于60%的数据, \(m <= 1000\) 对于100%的数据, \(1 <= n <= 1000,1 <= m <= 1,000,000\) 0 < 数字大小 <= 1,000,000,000 题解: 这里提供一种结构体指针线段树的写法: 做这道题,你首先要知道 \(gcd\) 的求法,由欧几里得算法可知: int gcd(int x, int y) { return y == 0 ? x : gcd(y, x % y); } 其次, \(gcd\) 满足区间可加性,即: \[ gcd(l, r) = gcd(gcd(l, k), gcd(k+1, r)),k\in[l, r]

BZOJ4771: 七彩树

寵の児 提交于 2019-11-30 06:08:50
4771: 七彩树 Time Limit: 5 Sec Memory Limit: 256 MB Submit: 2490 Solved: 715 [ Submit ][ Status ][ Discuss ] Description 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点。每个节点都被染上了某一种颜色,其中第i个节 点的颜色为c[i]。如果c[i]=c[j],那么我们认为点i和点j拥有相同的颜色。定义depth[i]为i节点与根节点的距离 ,为了方便起见,你可以认为树上相邻的两个点之间的距离为1。站在这棵色彩斑斓的树前面,你将面临m个问题。 每个问题包含两个整数x和d,表示询问x子树里且depth不超过depth[x]+d的所有点中出现了多少种本质不同的颜色 。请写一个程序,快速回答这些询问。 Input 第一行包含一个正整数T(1<=T<=500),表示测试数据的组数。 每组数据中,第一行包含两个正整数n(1<=n<=100000)和m(1<=m<=100000),表示节点数和询问数。 第二行包含n个正整数,其中第i个数为c[i](1<=c[i]<=n),分别表示每个节点的颜色。 第三行包含n-1个正整数,其中第i个数为f[i+1](1<=f[i]<i),表示节点i+1的父亲节点的编号。 接下来m行,每行两个整数x(1<=x<=n)和d(0<=d<n)

@codeforces - 1209G2@ Into Blocks (hard version)

做~自己de王妃 提交于 2019-11-30 05:53:51
目录 @description@ @solution@ @accepted code@ @details@ @description@ 定义一个序列是好的,当且仅当这个序列中,相等的两个数之间的所有数全部相等。 每次操作可以将某个元素值对应的所有元素修改成另一元素值。 一个序列的困难度定义为,将这个序列修改成好的序列的最少需要修改的位置数。 现在给定初始序列 a1, a2, ..., an 以及 q 次操作,每次操作为 i x,表示将第 i 个元素修改为 x。 计算初始时以及每次操作后序列的困难度。 Input 第一行包含两个整数 n 与 q (1≤n≤200000, 0≤q≤200000),表示序列长度与操作数。 第二行包含 n 个整数 a1, a2, ..., an (1≤ai≤200000),表示初始序列。 接下来 q 行每行两个整数 it, xt (1≤it≤n, 1≤xt≤200000),描述了一次操作。 Output 输出 q + 1 个整数,表示初始序列以及每次操作后的序列的困难度。 Example input 5 6 1 2 1 2 1 2 1 4 1 5 3 2 3 4 2 2 1 output 2 1 0 0 2 3 0 @solution@ 假如如果没有修改(即 easy 版本),应该怎么做? 首先假如某个元素值 k,它最左边出现的位置为 l[k]