线段树

CCF(除法):线段树区间修改(50分)+线段树点修改(100分)+线段树(100分)

被刻印的时光 ゝ 提交于 2019-11-29 05:38:24
除法 201709-5 这道题有很多种方法来做,最常用的就是线段树和树状数组。 如果使用线段树来做,就会想到区间修改的update函数。但是这里可能会涉及到v是1或者a[j]是0的情况,所以用这种方法会超时,最多50分。 可以修改一下代码,使用点修改来做这道题。在main函数里面增加一个循环,用来判断。 当然,还有一种方法就是树状数组,这种方法和上面这种方法运行时间相差无几,但是代码量大大减少。 需要注意的是,如果v是long long型,最好不要用scanf %lld的方式读入,否则超时。 使用线段树代码: //线段树求解 #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<vector> using namespace std; const int maxn=100005; int n,m; int a[maxn]; long long sum[maxn<<2]; void pushup(int id,int l,int r){ int lc=id<<1; int rc=id<<1|1; sum[id]=sum[lc]+sum[rc]; } void build(int id,int l,int r){ if(l==r){ sum

线段树模板题

心已入冬 提交于 2019-11-29 05:15:52
P3372 【模板】线段树 1 #include <iostream> #include <algorithm> typedef long long LL; using namespace std; const int MAXN = 1000000+5; LL arr[MAXN]; struct seg { int l, r, lz; LL v; }t[MAXN << 2];//lz延迟标记,l 左边界,r 右边界 int lch(int k) { return k << 1; }; int rch(int k) { return k << 1 | 1; }; inline void push_down(int k) { if (!t[k].lz) return; int mid = (t[k].l + t[k].r) >> 1, lz = t[k].lz; t[lch(k)].lz += lz; t[rch(k)].lz += lz; t[lch(k)].v += lz * (mid - t[lch(k)].l + 1); t[rch(k)].v += lz * (t[rch(k)].r - mid); t[k].lz = 0; } inline void push_up(int k) { t[k].v = t[lch(k)].v + t[rch(k)].v; } void

P3372 【模板】线段树 1 (区间查询)

*爱你&永不变心* 提交于 2019-11-29 05:13:11
P3372 【模板】线段树 1 题目链接: https://www.luogu.org/problem/P3372 题目: 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入格式 第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和 输出格式 输出包含若干行整数,即为所有操作2的结果。 输入输出样例 输入 #1 5 5 1 5 4 2 3 2 2 4 1 2 3 2 2 3 4 1 1 5 1 2 1 4 输出 #1 11 8 20 说明/提示 时空限制:1000ms,128M 数据规模: 对于30%的数据:N<=8,M<=10 对于70%的数据:N<=1000,M<=10000 对于100%的数据:N<=100000,M<=100000 (数据已经过加强^_^,保证在int64/long long数据范围内) 样例说明: // // Created by hanjinyu on 19-9-2. // #include<bits/stdc++

线段树的lazy标记

你。 提交于 2019-11-29 05:00:06
众所周知,当涉及到线段树的区间修改时,往往会引入lazy标记,通过懒惰标记的push_down优化区间修改和查询 如这道板题:   题目链接 1 #include <bits/stdc++.h> 2 #define Lson(x) ((x)<<1) 3 #define Rson(x) ((x)<<1|1) 4 using namespace std; 5 6 const int maxn =1e5; 7 int d[(maxn<<2)+10]; 8 int lazy[(maxn<<2)+10]; 9 int raw[maxn+10]; 10 void build(int s,int t,int p){ 11 if(s==t){ 12 d[p] = raw[s]; 13 return; 14 } 15 int mid = (s+t)>>1; 16 build(s,mid,Lson(p)); 17 build(mid+1,t,Rson(p)); 18 d[p] = d[Lson(p)] + d[Rson(p)]; 19 return; 20 } 21 22 void update(int L,int R,int C,int s,int t,int p){ 23 if(L==s&&t==R){ 24 d[p] = (R-L+1)*C; 25 lazy[p] = C; 26 return

模板——线段树维护最大子段和 SP1716 GSS3 - Can you answer these queries III

时光怂恿深爱的人放手 提交于 2019-11-29 03:51:05
${\color{Pink}{>>Question}}$ 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 #define ll long long 7 using namespace std; 8 9 template <typename T> void in(T &x) { 10 x = 0; T f = 1; char ch = getchar(); 11 while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} 12 while(isdigit(ch)) {x = 10*x + ch - '0'; ch = getchar();} 13 x *= f; 14 } 15 16 template <typename T> void out(T x) { 17 if(x < 0) putchar('-'),x = -x; 18 if(x > 9) out(x/10); 19 putchar(x%10 + '0'); 20 } 21 22 //-----------------------------------------------------------

线段树及例题(含题解)汇总(持续更新)

别等时光非礼了梦想. 提交于 2019-11-29 03:25:54
线段树及例题(含题解)汇总(持续更新) 该来的总要来,寒假没好好学,现在就得为寒假的懒买单(呜呜呜)。看了一天的线段树,虽然看懂还是很容易,毕竟就是一个特殊二叉树,但是实际应用却还是很复杂的,于是开始找些模板题敲敲,争取好好掌握这一数据结构。 至于不了解线段树基础知识的话,这有一大牛博客的传送门: 传送门 这里简单介绍下线段树存储:线段树本身就是二叉树,故有: 1、指针存储 2、数组存储( 重点讲下 ):由于线段树是 完全二叉树 ,所以要么没有左右孩子,要么一定有两个,而且左孩子为2 root,右孩子为2 root+1,于是可以用数组存储,通过下标寻找 难点在于数组大小:基本上为结点数 4倍 足够 线段树使用于和 区间统计 有关的问题: 比如某些数据可以按区间进行划分,按区间动态进行修改,而且还需要按区间多次进行查询, 主要操作有: 点修改,点查询,区间查询,区间修改(较难) 常见题型有: 区间最值、区间求和、区间染色、矩形问题、区间k大数、二维线段树、三维线段树 (小白瑟瑟发抖。。。) 用线段树解题,关键是要想清楚每个结点要存哪些数据(当然区间起终点,以及左右子节点指针是必须的(也可以通过数组代替))以及这些信息如何高效更新、维护、查询。不要一更新就更新到叶子结点,那样更新效率最坏就可能变成O(n)的了。 基本思路: 先建树,然后插入数据,然后更新,查询 一、区间最值 题目链接

Continuous Intervals 线段树

孤街浪徒 提交于 2019-11-29 02:35:20
题意:给出一个序列 ai 问有多少对 l r 满足 将 a[l]-a[r]之间的数sort一下 a[l]-a[r] 相邻的数字差值差值不大于1 非常巧妙的线段树 比赛的时候根本没啥头绪 对于每一个L 和都可能需要修改 那么用单调栈进行维护即可 cnt的话 用last来维护 对于那个-1 因为每次加入一个R 当L=R的那对LR 是一定满足条件的 所以最小值一定是-1 也就是最小值一定满足答案 所以这个-1也就没有意义 build的时候初始化任意值都可以 #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// const int N=1e5+10; int minn[N<<2],t[N<<2],n,m,col[N<<2],a[N]; ll ans; void

埃氏筛+线段树——cf731F

拜拜、爱过 提交于 2019-11-29 02:25:02
从2e5-1依次枚举每个数作为主显卡,然后分段求比它大的数的个数,这里的复杂度是调和级数ln2e5,即埃氏筛的复杂度、、 #include<bits/stdc++.h> using namespace std; #define ll long long #define N 200005 int cnt[N],n; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 ll num[N<<2]; void update(int pos,int v,int l,int r,int rt){ if(l==r){ num[rt]+=v; return; } int m=l+r>>1; if(pos<=m)update(pos,v,lson); else update(pos,v,rson); num[rt]=num[rt<<1]+num[rt<<1|1]; } ll query(int L,int R,int l,int r,int rt){ if(L<=l && R>=r){ return num[rt]; } int m=l+r>>1; ll res=0; if(L<=m)res+=query(L,R,lson); if(R>m)res+=query(L,R,rson); return res; } int main(){ cin>>n;

P4513 小白逛公园(线段树求区间最大子段和)

末鹿安然 提交于 2019-11-29 02:19:15
题目链接: https://www.luogu.org/problem/P4513 题目背景 小新经常陪小白去公园玩,也就是所谓的遛狗啦… 题目描述 在小新家附近有一条“公园路”,路的一边从南到北依次排着 n n个公园,小白早就看花了眼,自己也不清楚该去哪些公园玩了。 一开始,小白就根据公园的风景给每个公园打了分-.-。小新为了省事,每次遛狗的时候都会事先规定一个范围,小白只可以选择第 a a个和第 b b个公园之间(包括 a a、 b b两个公园)选择连续的一些公园玩。小白当然希望选出的公园的分数总和尽量高咯。同时,由于一些公园的景观会有所改变,所以,小白的打分也可能会有一些变化。 那么,就请你来帮小白选择公园吧。 输入格式 第一行,两个整数 N N和 M M,分别表示表示公园的数量和操作(遛狗或者改变打分)总数。 接下来 N N行,每行一个整数,依次给出小白 开始时对公园的打分。 接下来 M M行,每行三个整数。第一个整数 K K, 1 1或 2 2。 K=1 K = 1表示,小新要带小白出去玩,接下来的两个整数 a a和 b b给出了选择公园的范围( 1≤a,b≤N 1 ≤ a , b ≤ N)。测试数据可能会出现 a>b a > b的情况,需要进行交换; K=2 K = 2表示,小白改变了对某个公园的打分,接下来的两个整数 p p和 s s,表示小白对第 p

[BZOJ3693][线段树][Hall定理]圆桌会议

我们两清 提交于 2019-11-29 00:41:29
BZOJ3693 就是要判断有没有完美匹配,用Hall定理可知对于任意 l [ i ] , r [ j ] l[i],r[j] l [ i ] , r [ j ] ,若某一个 l [ k ] , r [ k ] l[k],r[k] l [ k ] , r [ k ] 被其包含,则对应的 a [ k ] a[k] a [ k ] 之和需要小于等于 r [ j ] − l [ i ] + 1 r[j]-l[i]+1 r [ j ] − l [ i ] + 1 (其实用脑子想也想的出来) 如果不是环的话我们将操作按 r r r 排序,把 l l l 离散化,从左到右做 要求 ∑ a [ k ] ≤ r [ i ] − l [ j ] + 1 \sum a[k]\le r[i]-l[j]+1 ∑ a [ k ] ≤ r [ i ] − l [ j ] + 1 ,即是 ∑ a [ k ] + l [ j ] − 1 ≤ r [ i ] \sum a[k] +l[j]-1\le r[i] ∑ a [ k ] + l [ j ] − 1 ≤ r [ i ] ,所以统计每个点的 ∑ a [ k ] + l [ j ] + 1 \sum a[k]+l[j]+1 ∑ a [ k ] + l [ j ] + 1 ,每扫进来一个 r [ k ] , l [ k ] r[k],l[k] r [ k ] ,