线段树

线段树模板

 ̄綄美尐妖づ 提交于 2020-02-04 22:19:32
线段树模板 单点更新+区间查询 # include <iostream> # include <stdio.h> # include <math.h> # include <string> # include <string.h> # include <algorithm> # define ll long long # define l(p) t[p].l //区间左端点 # define r(p) t[p].r //区间右端点 # define mid (l(p)+r(p))/2 # define sum(p) t[p].sum # define lp p<<1 //左孩子 # define rp (p<<1)|1 //右孩子 using namespace std ; const int maxN = 2e5 + 10 ; int a [ maxN ] ; struct Node { int l , r , sum ; } t [ maxN * 4 ] ; void build ( int p , int l , int r ) { l ( p ) = l ; r ( p ) = r ; if ( l == r ) { sum ( p ) = a [ l ] ; return ; } build ( lp , l , mid ) ; build ( rp , mid + 1

数列区间最大值-线段树-模板

眉间皱痕 提交于 2020-02-04 21:13:03
输入一串数字,给你 M 个询问,每次询问就给你两个数字 X,Y,要求你说出 X 到 Y 这段区间内的最大数。 输入格式 第一行两个整数 N,M 表示数字的个数和要询问的次数; 接下来一行为 N 个数; 接下来 M 行,每行都有两个整数 X,Y。 输出格式 输出共 M 行,每行输出一个数。 数据范围 1≤N≤105, 1≤M≤106, 1≤X≤Y≤N, 数列中的数字均不超过231−1 输入样例: 10 2 3 2 4 5 6 8 1 2 9 7 1 4 3 8 输出样例: 5 8 注意:读入的数据量较大,用scanf.优化后的cin也会超。 #include < iostream > #include < cstdio > #include < algorithm > using namespace std ; const int N = 100010 ; int w [ N ] ; int n , m ; struct Node { int l , r ; int sum ; } tr [ N * 4 ] ; void pushup ( int u ) { tr [ u ] . sum = max ( tr [ u << 1 ] . sum , tr [ u << 1 | 1 ] . sum ) ; } void build ( int u , int l , int r ) {

IOI2018

倖福魔咒の 提交于 2020-02-04 12:13:58
【IOI2018】组合动作(构造) 一种思路是:注意到后面的字符都和第一个字符不同,于是对每一位进行2次询问(不用3次,因为剩下的字符可直接确定)确定字符串,不太理想。 但是给询问的字符串长度<=4*n,这启示我们进行并行询问。实际上,假设现在答案字符串为S,先找到首位字符,询问$SAASABSACSB$(A,B,C是除了首位字符的字符)就能知道下一位的结果。(可以看代码)最后一个暴力即可。 但是首位字符需要3次询问,可以二分一下字符集,就可以降到2次询问。 #include <bits/stdc++.h> #include "combo.h" using namespace std; #define p press string guess_sequence(int n) { string r[3], a; if (p("AB")) { if (p("A")) { r[0] = "B"; r[1] = "X"; r[2] = "Y"; a = "A"; } else { r[0] = "A"; r[1] = "X"; r[2] = "Y"; a = "B"; } } else { if (p("X")) { r[0] = "A"; r[1] = "B"; r[2] = "Y"; a = "X"; } else { r[0] = "A"; r[1] = "B"; r[2] = "X

线段树(区间加区间统计)

爷,独闯天下 提交于 2020-02-03 14:49:22
#include <bits/stdc++.h> #define ll long long using namespace std; const ll maxn=2e5*5+10; struct re { ll x,y,w,z; }; re a[maxn]; ll b[maxn]; void up(ll k) { a[k].z=a[k*2].z+a[k*2+1].z; } void down(ll k) { a[k*2].w+=a[k].w; a[k*2].z+=(a[k*2].y-a[k*2].x+1)*a[k].w; a[k*2+1].w+=a[k].w; a[k*2+1].z+=(a[k*2+1].y-a[k*2+1].x+1)*a[k].w; a[k].w=0; } void build(ll k,ll l,ll r) { a[k].x=l,a[k].y=r,a[k].w=0; if (l==r) { a[k].z=b[l]; return; } ll mid=(l+r)/2; build(k*2,l,mid); build(k*2+1,mid+1,r); up(k); } void update(ll k,ll l,ll r,ll w) { if (a[k].y<l||a[k].x>r) return; if (l<=a[k].x&&a[k].y<=r) { a[k].w

寒假

最后都变了- 提交于 2020-02-03 14:48:27
1 G - Greg and Array CodeForces - 296C 差分+线段树 2 欧拉函数与中国剩余定理 3 Obtain The String CodeForces - 1295C binary_search+思维 4 V - Infinite Prefixes CodeForces - 1295B math 5 N - Aroma's Search CodeForces - 1293D math+greedy 6 Xor Path 牛客,HPU--C--LCA 7 U - Obtain a Permutation CodeForces - 1294E 思维 8 D. Minimax Problem Codeforces 1288D binary_search+二进制 9 -----差分简介------ 10 ATcoder E - Flatten 质因子分解求LCM 11 C - Dr. Evil Underscores CodeForces - 1285D 二进制 12 B - Fadi and LCM CodeForces - 1285C 质因子 13 C - Long Beautiful Integer codeforces 1269C 构造 14 线段树模板,区间(乘法+加法) 来源: https://www.cnblogs.com/Accepting/p

二维线段树(树套树)

混江龙づ霸主 提交于 2020-02-03 03:01:11
解析待写 例题: 2020 CCPC Wannafly Winter Camp Day5 I 题 代码: #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e3+10; int n, m1, m2; int x, y, xl, xr, yl, yr; ll w; ll a[N][N]; void add(){ a[xl][yl] += w; a[xl][yr+1] -= w; a[xr+1][yl] -= w; a[xr+1][yr+1] += w; } ll tree[4*N][4*N]; void up_y(int ox, int oy, int l, int r, int f){ if(l == r){ if(f) tree[ox][oy] = w; else tree[ox][oy] = max(tree[ox<<1][oy], tree[ox<<1|1][oy]); return ; } int mid = l+r >> 1; if(y <= mid) up_y(ox, oy<<1, l, mid, f); else up_y(ox, oy<<1|1, mid+1, r, f); tree[ox][oy] = max(tree[ox][oy<<1], tree

线段树详解

北城余情 提交于 2020-02-02 23:59:48
目录 线段树及其应用 1.建树 2.单点查询 3.单点修改 4.区间查询 5.区间修改 线段树及其应用 线段树的几个基础操作:建树,单点查询,单点修改,区间查询,区间修改。其代码的主要思想为二分。参考博客: https://blog.csdn.net/qq_39826163/article/details/81436440 数据结构: struct node { int l; //左端点 int r; //右端点 int sum; //区间和,因题目而异 int f; //懒标记 }tree[4*maxn+1]; 1.建树 建树的过程分为三步:1:给定左右端点的确定范围;2:如果是叶子结点,储存需要维护的信息;3:状态合并。下面是实现代码: void build(int l,int r,int cur) { tree[cur].l = l,tree[cur].r = r; if(tree[cur].l == tree[cur].r){ tree[cur].sum = arr[l]; return; } int mid = (l + r) >> 1; build(l, mid, cur << 1); build(mid + 1, r, cur << 1 | 1); pushup(cur); //状态合并 } 2.单点查询 单点查询与二分查询法基本一致,如果当前枚举的点左右端点相等

洛谷P5490 【模板】扫描线

橙三吉。 提交于 2020-02-02 05:19:21
半年前就听说过一种名为扫描线的神秘科技,但实际上学过后会发现其实就是一种线段树的用法,其中扫描线的线段树还和普通的线段树有所不同,一个是每个节点实际上是映射1e9的值,其次需要同时维护两棵线段树:flag记录当先节点是否全部被覆盖(只记录最深处的值且不pushup);sum记录当先线段中扫描到的长度(需要pushup但由于每次都是只用访问sum[1]所以不用pushdown)。另外需要注意的另外一点就是线段树是只根据左节点的建立的,所以有一些操作和一般的线段树不同。 总之,扫描线原理不难但是需要考虑的细节很多,代码中已经标记,不能写错了! #include <bits/stdc++.h> #define x first #define y second #define mid (l + r >> 1) #define lo (o << 1) #define ro (lo | 1) using namespace std; typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef vector<int> vi; const int maxn = 2e5 + 10; const int inf = 0x3f3f3f3f; const ll linf =

【线段树】[NOI2016]区间

柔情痞子 提交于 2020-02-02 00:16:50
题目 描述 在数轴上有 n 个闭区间 [ l 1 , r 1 ] , [ l 2 , r 2 ] , . . . , [ l n , r n ] 。现在要从中选出 m 个区间,使得这 m 个区间共同包含至少一个位置。换句话说,就是使得存在一个 x ,使得对于每一个被选中的区间 [ l i , r i ] ,都有 l i ≤ x ≤ r i 。 对于一个合法的选取方案,它的花费为 被选中的最长区间长度减去被选中的最短区间长度 。区间 [ l i , r i ] 的长度定义为 r i − l i ,即等于它的右端点的值减去左端点的值。 求所有合法方案中最小的花费。如果不存在合法的方案,输出 − 1 。 输入格式 第一行包含两个正整数 n , m ,用空格隔开,意义如上文所述。保证 1 ≤ m ≤ n 。 接下来 n 行,每行表示一个区间,包含用空格隔开的两个整数 l i 和 r i 为该区间的左右端点。 输出格式 只有一行,包含一个正整数,即最小花费。 样例一 input 6 3 3 5 1 2 3 4 2 2 1 5 1 4 output 2 explanation 如图,当 n = 6 , m = 3 时,花费最小的方案是选取 [ 3 , 5 ] 、 [ 3 , 4 ] 、 [ 1 , 4 ] 这三个区间,他们共同包含了 4 这个位置,所以是合法的。其中最长的区间是 [ 1 , 4

树状数组(入门篇)

不问归期 提交于 2020-02-01 20:23:55
学习过线段树之后,应该会觉得线段树在各种维护问题上代码量比较大,而且比较麻烦。主要原因就是因为线段树把每个大区间都分成两个小区间,直到分成单独点。但是在实际操作的时候,很多申请的区间节点都是用不上的,造成了空间的浪费,那么如何解决这一问题呢? 先引入前缀和的概念: 前缀和:对于某一数组a[n],其中前缀和数组s[n]定义为s 0 =0,s i =a[1]+…+a[i](1<=i<=n)。即a数组的前i(1<=i<=n)项和叫做该数组的前缀和。容易知道,a数组中的任意区间和都可以通过该前缀树组中的元素相减得到 有了前缀和,我们可以简化下列线段树: 怎么简化呢?我们把该线段树上的所有的右子树去掉,只保留所有的左子树,这样之后,右子树本该保留的值就拿父节点保留的值减去左子树保留的值可以得到 如上图,蓝色部分是线段树删去的保存的叶子节点,箭头表示它保存在上面的父区间中。现在的结构就叫做树状数组,下图是更直观的树状数组图: 我们可能会想,为什么要去掉右子树,去掉所有的左子树不行吗?在解释这个问题之前,我们先看下面这个函数 Lowbit()函数 Lowbit(x):将x在二进制分解下最低位的大小,通俗来讲就是找到从右向左第一个1所在位次k,其对应的大小为2 k 例如Lowbit(9),9的2进制为1001,显然最低位的大小为2 0 =1 下面给出一个结论来求Lowbit(x)