线段树

HDU_3333 Turing Tree 【线段树 + 离散化】

混江龙づ霸主 提交于 2019-11-29 00:22:52
一、题目    Turing Tree 二、分析   这题主要还是在区间的处理上。   为了保证区间内的数没有重复的,那么可以对区间按右端点从小到大排序,这样对原数组处理时,尽量保证不重复的元素靠右(可以假设右端点固定考虑),就可以保证区间求出来的值是不重复的,对于重复的就把前面位置出现的这个数减掉(即赋值为0)即可。   由于原数组的数比较大,要记录其之前的位置无法直接开数组,所以需要离散化。后面的就是普通的线段树的单点修改和区间查询了。 三、AC代码 #include <bits/stdc++.h> using namespace std; #define ll long long #define Min(a,b) ((a)>(b)?(b):(a)) #define Max(a,b) ((a)>(b)?(a):(b)) #define lson (rt<<1) #define rson (rt<<1|1) #define P pair<int, int> const int MAXN = 3e4; const int MAXQ = 1e5; ll A[MAXN + 13], Sum[MAXN<<2]; int Pre[MAXN + 13]; vector<ll> vec; struct node { int L, R, id; bool operator < (const

[线段树合并] Luogu P3605 [USACO17JAN]Promotion Counting晋升者计数

孤街浪徒 提交于 2019-11-28 23:51:12
给一棵 N 个点的树,每个点有一个权值,求每个点的子树中有多少个点的权值比它大。 考虑线段树合并,将权值离散化,每个点开一棵权值线段树。 求答案时直接在权值线段树上查询, 线段树合并时类似于可并堆。 要注意的是线段树要动态开点,合并时别忘了 up。 内存什么的最好算一下,数组别开小了。 1 #include<bits/stdc++.h> 2 #define rep(i,a,b) for(register int i=a;i<=b;++i) 3 #define rpd(i,a,b) for(register int i=a;i>=b;--i) 4 #define rep1(i,x) for(register int i=head[x];i;i=nxt[i]) 5 typedef long long ll; 6 const int N=2e5+5; 7 using namespace std; 8 inline int read(){ 9 int x=0,f=1;char ch=getchar(); 10 while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} 11 while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();} 12 return x*f; 13 } 14 struct Tree{int x

【模板】线段树 2

喜欢而已 提交于 2019-11-28 23:48:20
【模板】线段树 2 乘法懒标等于0也要下传,每次乘法操作对加法也要进行 #include<bits/stdc++.h> using namespace std; #define int long long const int maxn=1e5+10; int v[maxn*4],L[maxn*4],R[maxn*4],lazy1[maxn*4],lazy2[maxn*4]; int A[maxn]; int mod; void build(int l,int r,int x) { L[x]=l,R[x]=r; lazy1[x]=1,lazy2[x]=0; //v[x]=0; if(l==r) { v[x]=(A[l])%mod; return ; } int mid=(l+r)/2; build(l,mid,x*2); build(mid+1,r,x*2+1); v[x]=(v[2*x]+v[2*x+1])%mod; } void pushdown(int x) { // if(lazy1[x]): lazy1[x]==0 { v[x*2]=(v[x*2]*lazy1[x])%mod; v[x*2+1]=(v[x*2+1]*lazy1[x])%mod; lazy1[x*2]=(lazy1[x]*lazy1[x*2])%mod; lazy1[x*2+1]=(lazy1[x]

Remove Extra One 权值线段树

大憨熊 提交于 2019-11-28 23:07:52
最近疯狂练习线段树。。。 这道题题意很简单,在1-n中,找寻一个数,使得去掉这个数后,对于每个位置中满足 1<=j<i && a[ j ]<a[ i ] 的位置尽可能多。 我们考虑对于每个位置i的贡献,如果当前位置已经满足条件,那么前面任何数的删除,对这个位置实际上是没有贡献的,并且对于当前位置来说,删除这个位置相当于减去一个满足条件的位置。 如果当前位置可以通过删除一个数,变成可能的话,那么这个数字一定在前i位置里,并且只有一个大于这个数的位置,我们可以轻松是查询前i位比某个值大的数目,以及查询最大值所处于的位置(一直往右查询即可)。那么i位置,要想成为答案,就必须删除前面的最大值,我们删除前面最大值,相当于增加一个满足条件的位置。 如果前面有两个以上大于这个数,这个数肯定不能成为答案。 所以我们维护一个数组,这个数组vis[i]代表删除i,可以生成新的满足条件位置个数,取最大值中,值最小的。就是答案!!! 维护用权值线段树就可以啦!!! 1 #include<iostream> 2 #include<stdio.h> 3 #include<string.h> 4 #include<algorithm> 5 #define LL long long 6 #define lson rt<<1 7 #define rson rt<<1|1 8 #include<vector> 9

hdu 6730 线段树 2019-ccpc网络赛02

蹲街弑〆低调 提交于 2019-11-28 22:51:28
hdu 6730 线段树 2019-ccpc网络赛02 题意: 数组a时一个1~n的全排列,有如下两种操作 1 x,将a[x]+=1e7 2 r,k 查询大于等于k的最小值但不在数组中前r项中 (数组长度1e5,k<1e5) 思路: 首先观察可知在题目中查询的答案一定再 1~n+1 的范围内(因为k很小,操作一加的很大) 那么其实1操作就是取消掉禁用。之后考虑正着做比较难,则反着做查询 k~n+1 中最小的没被禁用的。 这里用一颗线段树就表示num[i]是否被禁用,查询的时候查询 k~n+1 中最小的没被ban掉的就好了,这里左右子树选择的时候再判断一下左子树上 k~mid 的最值就好。左右判断一个log,查询本身一个log。最终nlogn^2通过此题. 代码: #include <bits/stdc++.h> #define LL long long #define pii pair<int,int> #define PB push_back #define X first #define Y second using namespace std; int t,n,m,x; const int maxn = 5e5; const int inf = 0x3f3f3f3f; int a[maxn],b[maxn]; int rmin[maxn]; int ans,op,pos

hdu6703 线段树+set

心不动则不痛 提交于 2019-11-28 22:21:48
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6703 给你一个数组两种操作。操作一是将pos位置的数字加上 10 000 000;操作二是给你个r和k,问你最小的不小于k且没在数组a的[1,r]这个区间内出现过,并输出这个数。(pos,r,k均需异或上一次的答案,初始答案为零)。 因为k不大于n所以如果某个位置的数进行了操作一那么就代表下一次的操作二选出来的数可能是这个数。 我们用线段树维护最大的位置,线段树的节点表示值,节点存的是这个值在数组a中的位置。每次进行操作二时,我们查询线段树区间[k,n]内大于r的最小值。 因为如果进行了操作一后,线段树找出的值不一定就是最小的了,所以我们还要从所有进行了操作一的数中找出最小的且大于等于k的数,答案就是这两个数中最小的数。 #include<iostream> #include<algorithm> #include<set> using namespace std; #define ls l,mid,rt<<1 #define rs mid+1,r,rt<<1|1 #define maxn 100005 int maxx[maxn<<2],a[maxn],b[maxn],v[maxn]; int t,n,m; inline void pushup(int rt) { maxx[rt]

[loj6088]可持久化最长不降子序列

杀马特。学长 韩版系。学妹 提交于 2019-11-28 22:19:40
考虑二分求LIS的过程,就是维护一个序列,其中第i个数表示长度为i的最小结尾,而插入操作就是查找第一个大于x的位置并替换掉 用线段树维护,二分的过程也可以用线段树来完成,对线段树可持久化即可 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 500005 4 #define mid (l+r>>1) 5 int B,V,n,p,x,y,r[N],ans[N],f[N*30],ls[N*30],rs[N*30]; 6 int copy(int k){ 7 f[++V]=f[k]; 8 ls[V]=ls[k]; 9 rs[V]=rs[k]; 10 return V; 11 } 12 void build(int &k,int l,int r){ 13 f[k=++V]=0x3f3f3f3f; 14 if (l==r){ 15 if (!l)f[k]=-0x3f3f3f3f; 16 return; 17 } 18 build(ls[k],l,mid); 19 build(rs[k],mid+1,r); 20 f[k]=max(f[ls[k]],f[rs[k]]); 21 } 22 void update(int &k,int l,int r,int x,int y){ 23 k=copy(k); 24 if (l=

POJ_2828 Buy Tickets 【线段树】

北战南征 提交于 2019-11-28 22:05:08
一、题目    Buy Tickets 二、分析   首先可以明确的是每个人的位置都是定的,那么如果从输入数据从后往前看,最后面的人进来的时候,他前面的人数肯定是定的。   那么可以考虑,当从后往前推时,这个人插入的位置就是他前面有多少空位,假设他的位置比空位数少,那显然是不可以的,如果他的位置比空位多,那么后面的已经插入的,没有人来补这个位置了,所以显然也不合理,所以假设区间$[1,t]$刚好有$pos+1$个空位,那么它的位置应该就在最后一个空位处。 三、AC代码 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <cmath> 7 8 using namespace std; 9 #define ll long long 10 #define Min(a,b) ((a)>(b)?(b):(a)) 11 #define Max(a,b) ((a)>(b)?(a):(b)) 12 #define P pair<int, int> 13 #define lson (rt<<1) 14 #define rson (rt<<1|1) 15 const int MAXN = 2e5; 16 int ans

【数据结构】线段树

我与影子孤独终老i 提交于 2019-11-28 21:46:58
【数据结构】线段树 这两天被线段树折磨得痛不欲生,大把大把的时间被花在改错上,遂决定将我在这一知识点的学习笔记记录下来,供以后复习使用。 线段树是一种维护 区间信息 的数据结构,可以在O(logn)的时间复杂度内实现单点修改/查询以及区间修改/查询。应用范围包括区间求和,区间求最值等。 这篇笔记以维护区间和的线段树为例。 初始化 线段树的存储 我之前使用的是结构体来存储线段树,如下: struct SegTree { int l,r; //存储每个节点表示的区间 int sum; //存储区间和 int lazy; //存储延迟标记(下文提到,也是个令人抓狂的玩意儿) }segtree[400005]; 但当我写到区间查询时,我把用于存储节点区间的l,r和询问的l,r弄混了(!!!)。 这也是为什么我查错查了一个下午没查出来QAQ 其实,我们可以 直接使用数组存储线段树的数据以及懒惰标记,每个节点表示的区间现场算, 这样也更节省空间。 int tree[400005]; //这里存储的是区间和 int lazy[400005]; 当然如果你的线段树要维护多个东西,还是用结构体方便些,也更加直观。 其实嘛,如果你足够细心,就不会弄出我这种沙雕操作。存下l和r也挺好,可以减小代码常数,节省时间。 建树 众所周知,线段树是一棵完全二叉树,当父节点的编号为x时,它的两个子节点可表示为x<

线段树模板

☆樱花仙子☆ 提交于 2019-11-28 21:34:18
https://oi-wiki.org/ds/seg/ poj3468 区间增减值,区间和。 线段树思想:利用二叉树将每一个区间所需要的值都记录下来。 lazy思想:延迟对叶子节点的修改,要用到的时候才真的去修改,lazy数组记录修改的值。 #include <iostream> #include <cstdio> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 1e6+10; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 ll a[maxn]; ll d[maxn<<2]; ll lazy[maxn<<2]; void PushDown(ll rt,ll l,ll r) //下放懒惰标记 { if(lazy[rt]) { lazy[rt<<1] +=lazy[rt]; //左儿子懒惰标记加上当前父亲的懒惰值 lazy[rt<<1|1]+=lazy[rt]; //右儿子懒惰标记加上当前父亲的懒惰值 ll m=(l+r)>>1; d[rt<<1]+=lazy[rt]*(m-l+1); //左儿子的区间和加上父亲的懒惰标记值乘区间长度 d[rt<<1|1]+=lazy[rt]*(r-m); /