主席树

P3899|主席树+dfs序

自作多情 提交于 2020-01-23 15:45:32
理解题意后分两种情况: 1.b在a的上方: min(dep[p]-1,k)*(ll)siz[p] 因为(p点上方肯定有父亲结点b,我们不用管b是谁) 2.b在a的下方: (dep(p)+1 ~ dep(p)+k矩形框内的所有点子树个数和 所以思路:主席树维护同一深度下的各个结点子树个数和;下标是深度,权值维护的是子树个数和;在dfs序in和out时间戳上建立主席树,把树上问题转变为区间序列问题,利用dfs序时间戳的性质(子树编号在入时间戳和出时间戳的区间内),查询以p为根子树;所以问题就转变为了查询时间戳内区间内距离为k的点权和(相当于查询 矩形框 框住部分的点的个数了)。用线段树维护貌似也是可以的。 #include<bits/stdc++.h> using namespace std; typedef long long ll; int n,q; const int maxn = 3e5+10; vector<int> g[maxn]; int depth[maxn]; ll size[maxn]; int e = 0; int in[maxn],out[maxn],root[maxn]; int ma_siz[maxn],ma_dep[maxn]; struct Node{ ll v; int lc,rc; }T[maxn*24]; //递归计算dfs序 size子树大小

bzoj 泛做

爱⌒轻易说出口 提交于 2020-01-22 23:47:10
3003 这个题是这样的,对序列差分后,每个取反操作就是给两个端点的值取反,然后背包之后再状压就好了 4128 这题棒棒的QAQBSGS 23333 4176 这个杜教筛呃呃呃 大爷链接 3028 我要去学学生成函数 大爷链接 4025 我真TM是智商爆降了,这个东西明显的按时间分治一下就好了,管他什么lct 3498 一位大爷:“将所有点分成两类:度数 < sqrt(m)的和度数 > sqrt(m)的.先求包含第一类点的三元环个数.由于边很少,所以枚举2条边即可.由于一个点的度不超过sqrt(m),所以一条边最多被枚到(sqrt(m))次,最多枚M条边,所以这个操作时O(m sqrt(m))的.再求不包含第一类点的三元环个数.由于每条边贡献2个度,所以二类点的数量是O(sqrt(m))级的.直接枚举三个点,复杂度O((sqrt(m))^3)=O(m sqrt(m))所以算法总的复杂度是O(m*sqrt(m))的.” 5043 先发个 神犇友链 当时只知道暴力,f[i][j]表示第i位剩余j最小的k但是这样j为2^60太大无法忍受,所以可以倒着按位做表示这一位剩余j,一定满足j<=n,这样复杂度降为60n,好棒棒呦 4241 一样看以为莫队结果被怼啦 大爷链接 ,填填坑 2400 这题其实很简单,然而......因为是异或运算,所以每一位独立然后就是最小割了(捂脸 4036

信息学.学习计划/注意事项

别来无恙 提交于 2020-01-20 23:45:58
<学习计划> 一、重点学习新算法 1.平衡树splay,动态树LCT 2.(任意模数)NTT 3.莫队算法 4.带修主席树(树状数组套主席树),线段树/树状数组套平衡树 5.后缀数组/后缀自动机 二、刷题,复习、巩固在OJ上打星号的题目 <注意事项> 1.考试时无论题目有多难,都要努力想正解,不要理会别人,保持心态,想不出正解时要全力打暴力。 2.比赛开始时建各种文件夹要快,不耽误时间,离比赛结束15-20分钟时检查程序,把握好时间。 来源: https://www.cnblogs.com/mgh792821814/p/12219832.html

可持久化数组(主席树)

杀马特。学长 韩版系。学妹 提交于 2020-01-12 06:00:16
模板代码: #include<bits/stdc++.h> using namespace std; typedef long long LL; #define mid ((l+r)>>1) const int INF=1e9+7,MAXNODE=24e6+7,MAXN=1e6+7; int N,M,tmp[MAXN],rt[MAXN]; int val[MAXNODE],lson[MAXNODE],rson[MAXNODE],sz; void init(int &x,int l,int r){ x=++sz; if(l==r){ val[x]=tmp[l]; return; } init(lson[x],l,mid); init(rson[x],mid+1,r); } void modify(int &x,int l,int r,int p,int q,int v){ x=++sz; if(l==r){ val[x]=v; return; } lson[x]=lson[p]; rson[x]=rson[p]; val[x]=val[p]; if(q<=mid) modify(lson[x],l,mid,lson[p],q,v); else modify(rson[x],mid+1,r,rson[p],q,v); } int query(int x,int l,int r,int

HDU 4348 To the moon (主席树区间更新)

半腔热情 提交于 2020-01-05 03:16:53
题意:首先给你n个数,开始时间为0,最后按照操作输出 给你四种操作: 1. C l r d : 在(l,r)区间都加上d,时间加一 2. Q l r : 询问现在(l,r)的区间和 3. H l r t : 询问在t的时间(l,r)的区间和 4. B t : 直接回到t的时间 题解:首先是区间修改区间查询,可以想到线段树,接着就是询问历史版本与回到历史版本,这样就是主席树了 首先我们知道普通主席树是单点修改,并支持历史版本的区间求和与回到历史版本(就是这删除之后的树),仅仅只是因为它存了多棵线段树 而我们这儿是要进行区间修改,所以第一反应就是模拟线段树的lazy标记,并在查询时再更新再建树,但是这样会卡空间 因此我们需要这样想,模拟lazy标记进行重建树(最多建立2*log2(n)个节点)是必须的,但是查询时就不需要重建树了 这样我们就需要记录两个值:sum代表这一段中被增加区间的与此这一段的区间相交的总和,com代表这一段都需要增加这么多 这时我们查询时就需要每次加上com与待查询的区间相交的值(加上之前更新的),最后再包含的区间里加上sum再减去这儿com与待查询的区间相交的值(重复了) #include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector>

bzoj2653: middle

☆樱花仙子☆ 提交于 2020-01-02 12:07:55
首先,对于每个询问,我们二分答案 然后对于序列中大于等于中位数的数,我们把它们置为1,小于中位数的数,置为-1 那么如果一个区间和大于等于0,那么就资磁,否则就不滋磁 这个区间和呢,我们可以用主席树维护前缀和 [c,d]上的最大前缀和减去[a-1,b-1]上的最小前缀和,就是所有可用区间的最大区间和 这样要求主席树支持区间修改,正好之前没写过(捂脸),练一下 复杂度O(nlog^2n) (如果不资磁区间修改的话,也可以通过维护最大/小连续和的那套理论,达到同样的效果(好像所有题解都是这么做的)) (当然首先要离散化……) #include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <cstdlib> #include <algorithm> #define N 23333 using namespace std; inline int read(){ int ret=0;char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while ('0'<=ch&&ch<='9'){ ret=ret*10-48+ch; ch=getchar(); } return ret; } struct STnode{ int ls,rs;

主席树补充练习(未完待续)

喜你入骨 提交于 2020-01-02 12:06:39
1.(HDOJ6278)http://acm.hdu.edu.cn/showproblem.php?pid=6278 2.(CF961E)http://codeforces.com/problemset/problem/961/E 3.(CF1000F)http://codeforces.com/problemset/problem/1000/F 4.(CF916D)https://www.luogu.org/problemnew/show/CF916D 5.(CQOI2015)https://www.luogu.org/problemnew/show/P3168 6.(POI2014)https://www.luogu.org/problemnew/show/P3567 7.(SCOI2016)https://www.luogu.org/problemnew/show/P3293 8.(SDOI2010)https://www.luogu.org/problemnew/show/P2468 9.(P4137)https://www.luogu.org/problemnew/show/P4137 1.(HDOJ6278)http://acm.hdu.edu.cn/showproblem.php?pid=6278 题意:给定一个长度为n的序列,和q个询问,求每个询问[l,r

主席树——多棵线段树的集合

眉间皱痕 提交于 2019-12-22 12:13:45
主席树: (不要管名字) 我们有的时候,会遇到很多种情况,对于每一种情况,都需要通过线段树的操作实现。 碰巧的是,相邻两种情况下的线段树的差异不大。(总体的差异次数是O(N)级别的,均摊就是O(常数)的了) 显然的是,我们不能对于每种情况都建造一棵线段树。n^n 空间直接MLE无疑。 救命稻草是:发现相邻两种情况下的线段树的差异不大。 所以,我们是否可以让不同的线段树共用同一个节点呢?!?!? 这就是主席树的本质。也是精妙之处所在。 代码实现不是很麻烦。 我一般用传返回值形式,每次返回一个节点编号,便于设置儿子编号。比较方便。 注意的是,我们必须记录lson,rson,不能采用x<<1,x<<1|1的形式。因为没有这样的规律可循。 你不知道子节点和自己有什么关系。(这是谁家的孩子?公家的) 经典例题: 1.区间第k小(大)。 离散化必须的。 对于每一个区间节点开一个权值线段树 。i的线段树的节点l~r表示,在真正的区间1~i中,大小在l~r的数出现的次数。 记录每个线段树节点根的所在位置。 查询的时候,l-1,r两棵线段树同时出发,区间[a,b]sum值做一个差,就是l~r这个区间内,数值在[a,b]之间的数的个数。 对于区间第k小,选择左儿子区间做差,u<k,就进入右儿子,同时k-=u 否则进入左儿子。 区间第k大正相反。 对于n棵主席树,相邻两个主席树i,i

主席树 静态区间第k大

冷暖自知 提交于 2019-12-18 20:18:46
1 /* 2 主席树:对于序列的每一个前缀建一棵以序列里的值为下标的线段树(所以要先离散化), 3 记录该前缀序列里出现的值的次数; 4 记离散后的标记为1~n; (下面值直接用1~n代替;) 5 对于区间[x,y]的第k大的值,那么从root[x-1],root[y]开始, 6 t=root[y].[1,mid]-root[x-1].[1,mid] ,t表示区间[x,y]内值在[1,mid]的个数 7 先判断t是否大于K,如果t大于k,那么说明在区间[x,y]内存在[1,mid]的数的个数大于k, 8 也就是第k大的值在[1,mid]中,否则在[mid+1,r]中; 9 10 这样我们依次同时从root[x-1],root[y]往下走 11 当l==r时 第k大的值就是离散后标记为l的值; 12 13 如果每棵线段都建完整的化,n*(n<<2)肯定会mle, 14 我们发现对于前缀[1,i]和前缀[1,i+1]的线段树,如果b[i+1]<=mid (b[i+1]表示a[i+1]离散后的标记) 15 那么线段树i和线段树i+1的左边是完全相同的,根本不需要在建,只需要用指针指一下就好; 16 那么对于一棵新的线段树其实我们最多要建的节点数为log(n);nlog(n)的节点数还是可以忍受的; 17 18 19 20 */ 21 #include<cstdio> 22

我想要打一个主席树

别说谁变了你拦得住时间么 提交于 2019-12-14 01:43:46
这里提供了静态主席树及动态主席树(树状数组套主席树)的模板。 分别应用于静态区间第k小及动态区间第k小。 静态: #include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<cstring> #pragma GCC optimize(2) #pragma GCC optimize(3) #pragma GCC target("avx") #pragma GCC optimize("Ofast") #pragma GCC optimize("inline") #pragma GCC optimize("-fgcse") #pragma GCC optimize("-fgcse-lm") #pragma GCC optimize("-fipa-sra") #pragma GCC optimize("-ftree-pre") #pragma GCC optimize("-ftree-vrp") #pragma GCC optimize("-fpeephole2") #pragma GCC optimize("-ffast-math") #pragma GCC optimize("-fsched-spec") #pragma GCC optimize("unroll-loops")