线段树

PAT (Top Level) Practice 1009 Triple Inversions (35)

二次信任 提交于 2019-12-02 11:39:34
逆序对问题的升级版本(不知道的童鞋自行百度BIT/线段树求逆序对) 本体思路以三个数中间的数为基准,找前面比他大得数有几个 后面比他小的数有几个(可以算出来) 然后相乘+到res里即可 #include <bits/stdc++.h> using namespace std; #define N (int)1e5+10 int arr[N]; #define lc root<<1 #define rc root<<1|1 typedef long long ll; struct seg{ int l, r; ll he, lazy, tag; }t[4*N]; void build(int root, int l, int r) { t[root].l = l, t[root].r = r; t[root].lazy = 0; t[root].tag = -1; if (l == r) { t[root].he = 0; return; } int m = (l + r) >> 1; build(lc, l, m); build(rc, m+1, r); t[root].he = t[lc].he + t[rc].he; } void imptag(int root, ll change) { t[root].tag = change; t[root].he = (t[root]

【ICPC Aisa Yinchuan, 线段树(max,add)】G.Pot!!

懵懂的女人 提交于 2019-12-02 11:27:39
1 #include<iostream> 2 #include<string> 3 #include<queue> 4 #include<stack> 5 #include<vector> 6 #include<map> 7 #include<cstdio> 8 #include<cstdlib> 9 #include<algorithm> 10 #include<set> 11 #include<list> 12 #include<iomanip> 13 #include<cstring> 14 #include<cmath> 15 #include<limits> 16 using namespace std; 17 18 #define au auto 19 #define debug(i) cout<<"<debug> "<<i<<"<\debug>"<<endl 20 #define mfor(i,a,b) for(register int i=(a);i<=(b);i++) 21 #define mrep(i,a,b) for(register int i=(a);i>=(b);i--) 22 #define LLL __int128 23 #define Re register 24 #define il inline 25 #define mem(a,b)

线段树 区间修改 区间查询

感情迁移 提交于 2019-12-02 11:08:46
修改的时候要pushdown 查询的时候也要下放标记 #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const ll maxn=100000+10; ll tree[maxn<<2],tag[maxn<<2]; int a[maxn],x,y,val; char s[10]; void pushdown(int node,int len_L,int len_R) { if(tag[node]) { tag[node<<1]+=tag[node]; tag[node<<1|1]+=tag[node]; tree[node<<1]+=tag[node]*len_L; tree[node<<1|1]+=tag[node]*len_R; tag[node]=0; } } void creat(int node,int L,int R) { if(L==R) { tree[node]=a[L]; return; } else { int mid=(L+R)>>1; creat(node<<1,L,mid); creat(node<<1|1,mid+1,R); tree[node]=tree[node<<1

树链剖分

狂风中的少年 提交于 2019-12-02 10:58:28
“在一棵树上进行路径的修改、求极值、求和”乍一看只要线段树就能轻松解决,实际上,仅凭线段树是不能搞定它的。我们需要用到一种貌似高级的复杂算法——树链剖分。 树链剖分是将一棵树按照特殊的dfs序划分成链,从而使 树上任意一条链最多被划分为log(n)段, 同时保持的dfs序对子树操作的便利。 什么是树链剖分 树链剖分,它可以对一棵树进行轻重链剖分后用数据结构来维护每条重链。 比如下面这个问题:假设每个点有一个点权。如何把一棵树上的两个点uu,vv之间的简单路径上的所有点的点权增加dd? 这就是树链剖分能够解决的的一个基本问题。 接下来介绍一下树链剖分的详细过程。 轻重链剖分 树链剖分的第一步就是将一棵树进行轻重链剖分。 这一步决定了整个树链剖分的时间复杂度 。 引入几个概念: size[u]:以u为根的子树大小 wson[u]:在u的儿子中size值最大的那一个,称作uu的重儿子 dfn[u]:每个点的dfs序号。pre[tot],如果dfn[u]=tot,则pre[tot]=u 重链:指每个点与它的重儿子之间的连边(u—wson[u]) 轻链:在所有边中不是重的其他边 看图: 如上图,每一个带红点的点就是轻儿子;每一条加粗的的边就是重链,没有加粗的就是轻边。比如说对于点2,那么 wson[2]=6,size[2]=5,size[wson[u]]=size[6]=3。 dfn[u]

[题解]洛谷线段树2

社会主义新天地 提交于 2019-12-02 10:28:27
原题链 算法:线段树的懒标记之乘法与加法 思路: 对于懒标记(重难点),我们采用先乘后加的方法。 图片 代码 #include <bits/stdc++.h> using namespace std; struct node{//线段树定义 long long w,ad,mm; int l,r; }tree[800003]; long long n,m; long long p; void build(long long k,long long l,long long r){//建树 tree[k].l = l; tree[k].r = r; tree[k].mm = 1;//乘法标记初始值要为1,因为$0 × 0 = 0$为无效操作 if(l == r){//此节点为叶子节点 cin>>tree[k].w;//输入 tree[k].w %= p; return; } long long mid = (tree[k].l + tree[k].r) / 2; build(k * 2,l,mid);//构建左子树 build(k * 2 + 1,mid + 1,r);//构建右子树 tree[k].w = (tree[k * 2].w + tree[k * 2 + 1].w) % p;//上传 } void down(long long k){//懒标记下移 /

济南QBXT7月自闭游记

て烟熏妆下的殇ゞ 提交于 2019-12-02 08:17:07
Day -1 一觉睡到上午十点~~ 爽!!! 然后开始看番, \(emmm\) ,西片太太的狗粮真好吃,饱了饱了~ 下午接着看番 吃狗粮 ,大概两点开始钢文化课作业,三点不知道为什么又开始看番,四点时想到要去集训了,于是找道题练练手感。 从四点到六点,15分钟敲完了树剖加线段树,然后调了两个小时,最后发现 \(A\) 数组与 \(a\) 数组混了。。。 心态爆炸 \(ing\) 晚上匆忙想起来要收拾行李,结果光荣地把身份证忘掉了。。 然后滚粗睡觉去了。。。 Day 0 早上起来赶车,因为怕晕车什么东西也没吃,到了等大巴车的地方,大巴车竟然迟到了!! 顺便,等车的地方,味道一言难尽。。。 老师专门说了,不让带手机,虽然我还是带了,嘿嘿嘿。车上不敢太放肆,只敢戴着蓝牙听听歌,然后中间服务区维修,所以一路就到了济南,我也不知道一路上怎么过来的。。。 来了办理住房,因为没带身份证慌得一批,最后发现竟然可以办理临时的。。 \(SB\ old\ horse\) 一下午换了三次房间!!最后还是和 \(old\ horse\) 住一个房间!! 我佛了。。。 不过,原则不能变!!晚上该 \(high\) 还是 \(high\) ,一点滚粗睡觉, \(emmm\) 。 Day 1 还是一样的地方,不过到餐厅晚了,面包居然没了,还没有牛奶!!差评! 上午听一些极其简单的基础算法,老师说低估了我们的水平

洛谷P4198 楼房重建【线段树求前缀最大值个数】

蹲街弑〆低调 提交于 2019-12-02 06:47:26
题目描述: 小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段表示,其中Hi为第i栋楼房的高度。如果这栋楼房上任何一个高度大于0的点与(0,0)的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。 施工队的建造总共进行了M天。初始时,所有楼房都还没有开始建造,它们的高度均为0。在第i天,建筑队将会将横坐标为Xi的房屋的高度变为Yi(高度可以比原来大,也可以比原来小,甚至可以保持不变—建筑队这天什么事也没做)。请你帮小A数数每天在建筑队完工之后,他能看到多少栋楼房? 1<=Xi<=N,1<=Yi<=10^9,N,M<=100000 题目描述: 转成斜率之后就是求前缀最大值的个数(连续上升子序列长度) 单点修改,求值与前面的区间有关,考虑线段树。 如果记录区间最大值mx和前缀最大值的个数len,考虑如何合并两个区间: 就是左儿子的长度+在前面的最大值为mx[左儿子]的情况下右儿子的前缀最大值个数。 后面的东西相当于询问一个query(l,r,k),在前面最大值为k的情况下[l,r]的前缀最大值个数。 如果k>mx[l,mid],则答案为query(mid+1,r,k) 否则答案为query(l,mid,k)+query(mid+1,r,mx[左儿子]),而这个式子的右半部分与k无关,可以记录,实际上就是len[当前节点]-len[左儿子]。

被xgc吊打的第二天,Rose's simulate,线段树分治

大兔子大兔子 提交于 2019-12-02 06:38:20
正题 原题是清华集训2014的玄学。 因为对于i到j操作进行询问,所以考虑对操作建一棵线段树,每一个点存有一些区间,对于每一个点,这些区间的并为 ,每个区间存有两个值 ,对于这个区间内的每一个数k,表示经过我所管理的线段树操作后,会变成 。 可以把这些区间转化成多个断点,每次加入一个询问操作会多两个断点,对于线段树上的一条链贡献,所以断点个数总和不超过 ,但是遍历一条链,加断点的时间复杂度是不正确的,考虑一棵线段树的子树,当且仅当它满的时候,才把左右儿子进行合并,因为之前不可能访问到线段树中的这个节点。 合并两个端点可以直接过一遍,复杂度跟断点个数相关,所以插入时间复杂度还是 查询的时候,在线段树上找到对应的节点,二分找到对应的 ,把它们合并即可。 #include<bits/stdc++.h> #define ls now<<1 #define rs now<<1|1 using namespace std; const int N=100010; int T,n,mod,m,t=0; int A[N]; struct node{ int l,r,a,b; node operator+(const node q)const {return (node){0,0,1ll*a*q.a%mod,(1ll*b*q.a%mod+q.b)%mod};} }X; vector<node> tr

codeforces 600E dfs+线段树合并

爱⌒轻易说出口 提交于 2019-12-02 05:32:19
给你一棵有 n 个点的树 树上每个节点都有一种颜色 让你求每个点其子树出现最多的颜色,的节点编号 可以有多个最大值,一起计算. 裸的线段树合并,边dfs边合并就行了,最后把父亲放进去 #include<bits/stdc++.h> #define ll long long #define rep(ii,a,b) for(int ii=a;ii<=b;++ii) #define per(ii,a,b) for(int ii=b;ii>=a;--ii) #define forn(i,x,g,e) for(int i=g[x];i;i=e[i].next) #define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0) #define ull unsigned long long #define fi first #define se second #define mp make_pair #define pii pair<ll,ll> #define all(x) x.begin(),x.end() #define show(x) cout<<#x<<"="<<x<<endl #define show2(x,y) cout<<#x<<"="<<x<<" "<<#y<<"="<<y<<endl #define show3(x,y

线段树

旧巷老猫 提交于 2019-12-02 05:18:10
闲话 当我觉得我学习算法刚刚从萌新到入门的时候,一类给定一个区间然后给定一系列操作的题彻底的打击了我,那时我才醒悟,编程路上,我一直是萌新。 前言 啥是线段树? 线段树是一个具有树特性的数据结构,它是一颗 二叉搜索树 。如下图为区间[1,10]所建立的线段树 将每一个区间序列 二分 成小区间,线段树就存储小区间的信息,也就是每个小区间对应线段树中的一个结点。比如上图根节点对应[1,10] 对于每一个子节点而言,都表示整个序列中的一段子区间,如上图 橙色 节点; 对于每个叶子节点而言,都表示序列中的单个元素信息,如上图 绿色 节点; 子节点不断向自己的父亲节点传递信息,而父节点存储的信息则是它的每一个子节点信息的整合,也就是父亲是儿子们的 并 。 由于线段树的二分性质,对每一个子节点来说,左儿子的区间小于右儿子的区间,所以线段树也是 平衡树 。 有啥用? 将需要处理的信息看成一个个点,也就是叶子节点,然后通过父亲节点来将信息整合,做到通过树结构来进行操作对节点信息进行增删查改,大大降低复杂度。 最简单的应用就是记录区间是否被覆盖,随时查询当前被覆盖区间的总长度。 既然线段树利用区间二分建树,那么对子区间进行操作,只需要从根节点通过递归找到此区间即可, 一次操作时间肯定与树的高度有关,由于二叉树搜索树的关系,它的高度为log 2 (n), 所以完成一次操作的时间为O(log(n))。