线段树

[COGS 755]山海经:线段树

馋奶兔 提交于 2020-01-05 03:07:23
网上似乎这道题的题解很少?写一个吧 我跟这道题的渊源追溯到了上个学期刚刚学线段树的那一天。。。 当时线段树专题前边的题都是一些板子就不一会就水过了,然后就看到了最后一题的它:山海经 那一个上午,我竭尽全力,却毫无收获。 后来我下午继续肛还是肛不动,但是mikufun大神,在刚学线段树的阶段,把这道我现在都要写30min的难题给A了! 他当时的NB代码: 1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 struct tree{ 5 int l,r,da,dam,dal,dar; 6 int lme,lmr,le,lr; 7 }t[1000000]; 8 void build(int l1,int r1,int k){ 9 t[k].l=l1,t[k].r=r1; 10 if(l1==r1){ 11 scanf("%d",&t[k].da); 12 t[k].dal=t[k].dam=t[k].dar=t[k].da; 13 t[k].le=t[k].lme=t[k].lmr=t[k].lr=l1; 14 return; 15 } 16 int mid=(l1+r1)/2; 17 build(l1,mid,k*2); 18 build(mid+1,r1,k*2+1); 19 t[k].da=t[k*2]

HDU 4325 线段树离散化

谁都会走 提交于 2020-01-05 03:07:14
线段树离散化 1.输入完所有数据,对开花时间离散化 2.区间更新,点查询,LAZY操作。。 View Code #include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> #include<vector> using namespace std; #define MAXN 51000 struct node { int left, right; int num; int sum; int lazy; }seg[500010]; int N, M; struct flower { int a,b; }p[101000]; int v[200010]; int hashx[201000]; void build(int l, int r, int root) { int mid = (l + r) / 2; seg[root].left = l; seg[root].right = r; seg[root].num = 0; seg[root].lazy = 0; seg[root].sum = 0; if( l == r ) { return; } build(l,mid,root*2); build(mid+1,r,root*2+1); seg[root].sum = seg[root*2]

各种骚操作线段树

你说的曾经没有我的故事 提交于 2020-01-05 03:06:48
线段树是世界上最美的数据结构(主要记录一些有意义的线段树.....特别是骚操作 1.uestc1425 Another LCIS http://acm.uestc.edu.cn/#/problem/show/360 题意:两种操作 对于一段区间的数加上c 查询最长连续上升序列 题解:彻底弄清楚区间更新lazy的含义 就是切水题 直接区间更新然后区间合并用点小技巧即可 #include <iostream> #include <algorithm> #include <cstdio> #define N 100005 using namespace std; typedef struct node{ int l;int r;int l1;int len1;int r1;int len2; int len;int flag; }node; node d[N<<2]; int a[N]; void up(int root){ d[root].l1=d[root<<1].l1;d[root].r1=d[root<<1|1].r1; if(d[root<<1].r1<d[root<<1|1].l1){ d[root].len=max(d[root<<1].len,max(d[root<<1].len2+d[root<<1|1].len1,d[root<<1|1].len)); if(d

线段树练习3

我的梦境 提交于 2020-01-05 03:06:33
题目传送: http://codevs.cn/problem/1082/ 1082 线段树练习 3 时间限制: 3 s 空间限制: 128000 KB 题目等级 : 大师 Master 题解 题目描述 Description 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和。 输入描述 Input Description 第一行一个正整数n,接下来n行n个整数, 再接下来一个正整数Q,每行表示操作的个数, 如果第一个数是1,后接3个正整数, 表示在区间[a,b]内每个数增加X,如果是2, 表示操作2询问区间[a,b]的和是多少。 pascal选手请不要使用readln读入 输出描述 Output Description 对于每个询问输出一行一个答案 样例输入 Sample Input 3 1 2 3 2 1 2 3 2 2 2 3 样例输出 Sample Output 9 数据范围及提示 Data Size & Hint 数据范围 1<=n<=200000 1<=q<=200000 分类标签 Tags 点此展开 代码 堆 #include<cstdio> #include<iostream> using namespace std; #define N 801000 #define mid ((l+r)>>1) #define lc (k

hdoj 4325 Flowers 线段树+离散化

随声附和 提交于 2020-01-05 03:05:23
hdoj 4325 Flowers 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4325 思路: 直接线段树,按照花的开放区间的大小建树,要注意虽然花的周期数据可能会达到1e9,这样的话线段树开四倍时不可能的。但是我们可以看到一共可能的数据时N行,那么每行两个数,再开4倍的区间。计算下来,在离散化的帮助下,我们只需要开8*N被的线段树即可。 另外询问的数据也需要放入离散化的范围,如果不这样做,有可能在询问时使用lower_bound函数会导致数据的改变,询问的原数据发生变化。 eg:1~3 7~10 询问6,结果应该时0,但因为lower_bound的原因询问时使用7,得到结果1。etc. 代码: #include <iostream> #include <algorithm> #include <stdio.h> #include <string.h> #include <math.h> using namespace std; const int maxn = 1e5+5; struct node { int l,r,sum,lazy; inline void update(int val) { lazy+=val; sum+=val; } } tr[maxn*8]; int a[maxn],b[maxn],c[maxn<<1

[HDOJ4325]Flowers(树状数组 离散化)

梦想与她 提交于 2020-01-05 03:04:24
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4325 关于离散化的简介:http://blog.csdn.net/gokou_ruri/article/details/7723378 假如数据太大,无法作为数组下标来保存对应的属性而采取的一种方法。只需要关注相对大小即可。 我们记下所有的时间数据,再排序。通过二分查找快速定位元素的位置,然后在线段树或者树状数组上仅仅更新这个映射过后的下标位置。因为不需要从线段树或树状数组上直接获取数据(单纯的线段树或树状数组本身是没有意义的,需要搭配相应的数据操作才可以使其称之为线段树或树状数组),也就是说我们更新和查询都是要通过这样一次定位。这样可以解决空间不足的问题。排序后要去重,否则更新到时候可能会更新两次。 1 #include <algorithm> 2 #include <iostream> 3 #include <iomanip> 4 #include <cstring> 5 #include <climits> 6 #include <complex> 7 #include <fstream> 8 #include <cassert> 9 #include <cstdio> 10 #include <bitset> 11 #include <vector> 12 #include

HDU4578 Transformation 线段树

≡放荡痞女 提交于 2020-01-03 00:52:28
这个题让我重新学习了加 乘 在区间的操作 题解:http://blog.csdn.net/guognib/article/details/25324025?utm_source=tuicool&utm_medium=referral 代码:也是参考上面的写的 注:确实有优先级,加只影响自己,乘会影响加,重新设定值会清零所有的标记 所以向下传的时候,乘和加的操作都晚于最后一次设定值,然后乘的操作要先于加 所以要先传递set 然后是mul 然后是add #include <stdio.h> #include <string.h> #include <string> #include <math.h> #include <stack> #include <vector> #include <algorithm> using namespace std; typedef long long LL; const int N=1e5+5; const int mod=10007; int q[3][N<<2],setval[N<<2],add[N<<2],mul[N<<2]; void pushup(int rt){ for(int i=0;i<3;++i) q[i][rt]=(q[i][rt<<1]+q[i][rt<<1|1])%mod; } void downset(int rt,int

hdu4578 Transformation 线段树

对着背影说爱祢 提交于 2020-01-03 00:52:05
Yuanfang is puzzled with the question below: There are n integers, a 1 , a 2 , …, a n . The initial values of them are 0. There are four kinds of operations. Operation 1: Add c to each number between a x and a y inclusive. In other words, do transformation a k <---a k +c, k = x,x+1,…,y. Operation 2: Multiply c to each number between a x and a y inclusive. In other words, do transformation a k <---a k ×c, k = x,x+1,…,y. Operation 3: Change the numbers between a x and a y to c, inclusive. In other words, do transformation a k <---c, k = x,x+1,…,y. Operation 4: Get the sum of p power among the

【HDU4578 Transformation】线段树

一曲冷凌霜 提交于 2020-01-03 00:51:47
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4578 题意:有一个序列,有四种操作: 1:区间[l,r]内的数全部加c。 2:区间[l,r]内的数全部乘c。 3:区间[l,r]内的数全部初始为c。 4:询问区间[l,r]内所有数的P次方之和。 思路:比较复杂的线段树操作。只有一个询问操作,那就是询问[l,r]之间数的p次方之和,我们不可能全部查询的节点,会TLE,最好的情况就是查询到一段[a,b],这段区间内所有的值都相等,那么返回(b-a+1)*val 的值即可。 根据询问操作我们即可意识到我们要维护的是区间内所有值都相同的情况的区间。对于覆盖和加乘操作,我开始以为向下传递两层即可,这样是错误的,因为即可传递下去两层,还是有可能同时存在加乘操作。所以我们可以分两种情况讨论:1、当为覆盖操作时,直接覆盖区间即可,并且把标记的加乘操作赋为初始值。2、当为加乘操作时,先判断当前区间段是否为相同的值,是的话直接加乘,维护这个相同的值即可。如果不相同,看区间是否已有加乘标记,把这个加乘标记一直传递下去,知道遇见那个区间段区间所有值的相同停止。最后把这个加乘赋给最开始的区间段。简单的说就是,覆盖操作可直接维护,不是覆盖操作的话,区间只能保留一个加乘操作。 1 #include<iostream> 2 #include<cstdio> 3

HDU4578 Transformation【线段树】

谁都会走 提交于 2020-01-03 00:51:27
< 题目链接 > <转载于 >>> > 题目大意: 有一个序列,有四种操作: 1:区间[l,r]内的数全部加c。 2:区间[l,r]内的数全部乘c。 3:区间[l,r]内的数全部初始为c。 4:询问区间[l,r]内所有数的P次方之和。 解题分析: 不可能全部查询的节点,最好的情况就是查询到一段[l,r],这段区间内所有的值都相等,那么返回(r-l+1)*val 的值即可。只要标记区间内的所有数是否相同,并记录下区间内所有数相同的区间的值即可。每次询问时查询到区间内所有值相同的区间即可。 1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 typedef long long ll; 7 const int mod=10007; 8 const int M =1e5+5; 9 10 #define Lson rt<<1,l,mid 11 #define Rson rt<<1|1,mid+1,r 12 int n,m; 13 bool cnt[M<<2]; 14 ll tr[M<<2]; 15 void Pushdown(int rt){ 16 if(cnt[rt]){ 17 cnt[rt<<1]=cnt[rt<<1|1]=true; 18 tr[rt<<1]