线段树

树上 LIS 线段树合并+set

寵の児 提交于 2019-12-06 07:43:23
读错题了,然后写了一个树上 LIS,应该是对的吧...... code: #include <bits/stdc++.h> #define N 200005 #define LL long long #define setIO(s) freopen(s".in","r",stdin) using namespace std; struct seg { #define lson t[x].ls #define rson t[x].rs int tot; struct node { int ls,rs,maxx; }t[N*50]; int newnode() { return ++tot; } void update(int &x,int l,int r,int p,int v) { if(!x) x=newnode(); t[x].maxx=max(t[x].maxx,v); if(l==r) return; int mid=(l+r)>>1; if(p<=mid) update(lson,l,mid,p,v); else update(rson,mid+1,r,p,v); } int merge(int x,int y) { if(!x||!y) return x+y; int now=newnode(); t[now].maxx=max(t[x].maxx,t[y].maxx)

PKUWC2018题解

孤人 提交于 2019-12-06 06:27:43
按照 \(\texttt{loj}\) 的顺序写的 「PKUWC2018」Minimax 比较神仙的线段树合并,可能是我对于线段树合并还了解的不够透彻吧. 很显然可以对于每一个点的取值离散化后 \(dp\) 概率对吧. \[ \begin{align} dp_{u,i}&=dp_{l,i}\times(\sum_{j=1}^{i-1}dp_{r,j}*p+\sum_{j=i+1}^{tot}dp_{r,j}*(1-p))\\ &+dp_{r,i}\times(\sum_{j=1}^{i-1}dp_{l,j}*p+\sum_{j=i+1}^{tot}dp_{l,j}*(1-p)) \end{align} \] 这个东西的转移需要一个前缀和一个后缀和. 然后线段树合并的套路就是对于这个东西在合并左右子树线段树的时候记录一个和.如果要返回直接打乘法标记上去. 很清奇 代码 来源: https://www.cnblogs.com/fexuile/p/11965452.html

AC自动机fail树上dfs序建线段树+动态memset清空

纵饮孤独 提交于 2019-12-06 03:31:08
题意: http://acm.hdu.edu.cn/showproblem.php?pid=4117 思路: https://blog.csdn.net/u013306830/article/details/77586562 主要就是卡你内存,AC自动机的字典树得要用了再清空。 代码有点长吧。。。 1 #include <cstdio>//sprintf islower isupper 2 #include <iostream>//pair 3 #include <string.h>//strstr substr strcat 4 #include <queue>//priority_queue<int, vector<int>, greater<int> > q;//less 5 using namespace std;//next_permutation(a+1,a+1+n);//prev_permutation 6 #define mem(a,b) memset(a,b,sizeof(a)) 7 #define pr printf 8 #define sc scanf 9 #define ls rt<<1 10 #define rs rt<<1|1 11 const int N=3e5+10; 12 13 char s[N]; 14 int pos[20004],val

Luogu P3605 [USACO17JAN]Promotion Counting晋升者计数

痴心易碎 提交于 2019-12-06 00:15:07
题目 一种可行并且非常优秀常数小一大截的做法是BIT并且非常显然。 所以我们以这道题为例题讲一下线段树合并。 线段树合并要做的就是把两棵线段树对应位置的值全部加起来得到一棵新的线段树。 以下是一种可行的方法: 我们从根节点开始往下做,如果要合并的两棵线段树中有一棵线段树不存在当前节点,那么我们可以直接返回另一棵线段树的当前节点,因为当前节点及其子树内的信息都由这棵线段树决定。 否则我们合并两棵线段树对应位置的信息,然后递归左右儿子。 假设我们总共插入了 \(n\) 条信息,那么线段树的总结点个数是 \(n\log n\) 级别的,时间复杂度也为 \(O(n\log n)\) 。 然后回到这一题,我们可以把权值离散化,每个节点开一个动态开点权值线段树,然后自底向上线段树合并。 因为总共插入的信息是 \(n\) ,所以复杂度为 \(O(n\log n)\) 。 但是常数贼大,跑得比BIT慢到不知道哪里去了。 #include<bits/stdc++.h> #define pb push_back #define mid ((l+r)>>1) using namespace std; namespace IO { char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[15],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21); char Get(

[模板]线段树

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-05 22:22:40
题目描述 如题,已知一个数列,你需要进行下面两种操作: 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数据范围内) #include<bits/stdc++.h> using namespace std; int a[1000],val[1700000],lazy[1700000],m,n,op,v,x,y; void push_up(int root

线段树模板

你说的曾经没有我的故事 提交于 2019-12-05 18:15:41
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); /

线段树学习笔记

风流意气都作罢 提交于 2019-12-05 17:35:16
1 #include<iostream> 2 using namespace std; 3 struct tree{ 4   int l,r,sum; 5 }t[1000001]; 6 int a[1000001],n,p,x,y,m; 7 inline void build(int root,int left,int right) 8 { 9   t[root].l=left;t[root].r=right; 10   if(left==right){t[root].sum=a[left];return;} 11   int child(root<<1),mid((left+right)>>1); 12   build(child,left,mid);build(child+1,mid+1,right); 13   t[root].sum=t[child].sum+t[child+1].sum; 14 } 15 inline int search(int root,int left,int right) 16 { 17   if((t[root].l>=left)&&(t[root].r<=right)) 18     return t[root].sum; 19   if((t[root].r<left)||(t[root].l>right)) 20     return 0;

线段树(区间树)

て烟熏妆下的殇ゞ 提交于 2019-12-05 12:37:13
使用场景 区间查询成绩,如:在60-100分分学生 区间数统计,如:2018年注册用户中学习时长最长的用户 区间染色,如给一面墙染色,不同区间染不同色,查看某段区间内是什么颜色 示例(求和线段树) 线段树性质 不是完全二叉树 是平衡二叉树 来源: oschina 链接: https://my.oschina.net/HaverLee/blog/3137387

线段树

橙三吉。 提交于 2019-12-05 12:15:38
首先我们先明确两件事情! 1. 线段树他是个树! 2. 线段树是基于一个数组生成的! 好的这就已经大概勾勒出线段树美丽的轮廓了!那我们先来看一张照片。其中树的部分已经用看起来非常像树的颜色涂好了。 在这里插入图片描述 好那么废话不多讲我们就来说这个树是怎么长出来的吧。 我们要知道的是,树的每个节点上记录了一个区间。比如说,根节点记录了区间[1,8] [1,8],刚好是整个数组的长度。那么其他节点呢?这就是线段树的巧妙之处了。一个节点有两个子节点,且它们平分自己的区间。因此,根节点的两个子节点就分别对应了[1,4][1,4]和[5,8][5,8]。接下来[1,4][1,4]这个节点的两个子节点就是[1,2][1,2]和[3,4] [3,4]。 标上的每个节点代表的区间的照片如下。 在这里插入图片描述 最下面那一排为什么没有标呢?因为叶子节点刚好对应一个长度为1 1的区间,即从左到右分别为Unexpected text node: '&ThinSpace;' [1,1],[2,2],⋯,[8,8]。显然它也不会有儿子了。 哦我的天,你已经学会怎么基于数组建立线段树了!我相信到现在你应该还没用到2 2分钟吧! (其中看废话还要占1 1分钟) 还有一个小细节,比如假设你有一个区间[1,3] [1,3]它的长度是奇数这时怎么平分呢?其实左右那边长一点都没有关系,因此放心用你的整除号就行了。

浅谈主席树

旧时模样 提交于 2019-12-05 11:42:05
浅谈主席树 主席树,又名可持久化线段树,函数式线段树 (我也不知道啥意思) 。之所以叫主席树是因为发明人黄嘉泰姓名缩写是hjt (知道是谁吧) 首先,可持久化线段树,顾名思义 它是持久的 ,它支持询问过去版本,也就是说在过去某一次操作时的树,那么这怎么实现呢? 例题1: 给你一个长度为 \(n\) 的数组 \(a_1,a_2,...,a_n\) ,现在有 \(m\) 次操作: 1.将 \(a_i\) 变为 \(x\) 2.询问在第k次操作后, \(\Sigma_{i=l}^r a_i\) 的值 样例输入 4 1000 200 30 4 5 1 3 50 1 2 600 2 0 1 4 2 1 1 4 2 2 1 4 样例输出 1234 1254 1654 和以往不同,现在询问是对某一次的操作后的序列做询问。 如果用线段树维护区间和,那我们需要存下每次修改完后的线段树。 一个线段树需要 O(n) 的空间,显然不能存下 n 颗线段树,但是我们可以从这里找找突破口。 不妨先考虑最基本的线段树 第一次操作:把第 3 个位置改为 50 可以发现的是,这颗线段树和上一颗线段树只有 \(logn\) 个节点发生了变化。 第二次操作:把第 2 个位置改为 600 可以发现的是,这颗线段树和上一颗线段树同样也只有 \(logn\) 个节点发生了变化 我们发现,每一次单点修改,发生改变的节点只有 \