主席树

Count on a tree 树上主席树

自作多情 提交于 2019-12-02 02:23:25
Count on a tree 树上主席树 给 \(n\) 个树,每个点有点权,每次询问 \(u,v\) 路径上第 \(k\) 小点权,强制在线 求解区间静态第 \(k\) 小即用主席树。 树上主席树类似于区间上主席树,我们利用前缀和相减获得区间的信息,树上主席树也是这样,维护一个到根节点的前缀和。对于 \((u,v)\) 路径, \(sum[u]+sum[v]-sum[lca(u,v)]-sum[fa[lca(u,v)]]\) 即可获得树上 \(u,v\) 路径的区间信息,然后按照区间查询即可。 #include <cstdio> #include <algorithm> #define MAXN 1001000 #define MAXM MAXN*30 #define LOG 30 int head[MAXN],nxt[MAXN*2],vv[MAXN*2],tot; inline void add_edge(int u, int v){ vv[++tot]=v; nxt[tot]=head[u]; head[u]=tot; } int n,m,s,cnt; int f[MAXN][31],dep[MAXN]; int rot[MAXN]; int val[MAXN],idx[MAXN]; int tre[MAXM],sl[MAXM],sr[MAXM]; void build

[CF707D]Persistent Bookcase_主席树_bitset

廉价感情. 提交于 2019-12-01 23:36:55
Persistent Bookcase 题目链接 : http://codeforces.com/contest/707/problem/D 注释 :略。 题解 : 发现虽然$q\le 10^5$但是网格是$1000\times 1000$的,而且每次操作只会操作一行。 故此我们考虑按照行来搞。 想到每次暴力重新建一行,但是空间开不下,我们用$bitset$即可。 但是我们又面临一个问题,即:回到某一个时刻。 这个很难弄,最简单的支持可持久化的数据结构是主席树,所以我们对行建主席树。 每次修改操作我们都新开一个$bitset$,主席树的第$i$个叶子表示的是第$i$行对应哪一个$bitset$。 时间复杂度为$O(\frac{np}{32} +plogn)$。 代码 : #include <bits/stdc++.h> #define setIO(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout) #define N 400010 using namespace std; bitset <1010 > b[N], mdl; char *p1, *p2, buf[100000]; #define nc() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000,

浅谈主席树

倾然丶 夕夏残阳落幕 提交于 2019-12-01 12:58:50
我也不知道为啥突然跑来写这个东西…… 可能最近考太频繁??权当攒RP了。 说的好像真的有人会看一样。 0/0:引言 主席树,全名可持久化线段树,由一位名叫黄嘉泰(hjt)的大神在考场上yy出来。 所谓可持久化线段树,就是可以查询历史更新信息的线段树。 假如我有一棵线段树,维护一个长度为n的序列,称为历史版本1。 随后我对它进行m次操作,使其发生变化称为历史版本2、历史版本3……历史版本n。 此时我要查询历史版本3中的某一个区间的信息,该怎么办? 重新建树?$n,m \leq 1e5$。 啊啊啊啊啊啊啊啊啊啊…… 咦,那闪耀着救世主光辉的数据结构是…… 当然是: 主席树! 前置技能点: 动态开点线段树(不仅省空间,还可以进化成为主席树!) 前缀和思想(普遍的优化手段,静态区间查询的平民神器!) 0/1:思想 对于上面引言中提到的问题,我们考虑一个建树的过程。(以下仅考虑值域为8的情况) 最暴力的思想是,拿到一棵空线段树,我们分别建立它的历史版本以供最终查询。 建树过程如下: 1.在历史版本1中插入一个元素$3$ 2.新建一棵树称为历史版本2,复制之前的树并插入一个元素$6$。 3.再新建一棵树,插入一个元素$8$ 点数爆增有没有。 然后我们就发现,每插入一个单点的时候,整棵树的信息并非全部发生了变化。 那么新建一棵树就会放弃对这些信息的利用,浪费了空间。

主席树(可持久化线段树)

狂风中的少年 提交于 2019-12-01 09:57:02
模板介绍 基础要求 线段树 能灵活运用 线段树 前缀和,差分 概念 可持久化:在某个历史版本上更改;查询某个历史版本上的值 引入 洛谷P3919 可持久化数组 这道可持久化线段树的题 大概就是单点修改&单点查询 代码大致就是在线段树的基础上改变她存点的方式 以前 tree[k].l == k << 1 tree[k].r == k << 1 | 1 对于可持久化线段树 tree[k].l != k << 1 tree[k].r != k << 1 | 1 inline int tree_build(int k,int l,int r) { k = ++cnt; 每次这样来存点 但l和r仍然保留 表示一个递归和原序列位置的过程 if(l == r) { tree[k].val = seq[l]; return k; } int mid = l + r >> 1; tree[k].l = tree_build(tree[k].l,l,mid); tree[k].r = tree_build(tree[k].r,mid + 1,r); return k; } 大概酱紫 #include <map> #include <cstdio> #include <iostream> using namespace std; #define reg register int #define

洛谷 P2633 Count on a tree 题解

荒凉一梦 提交于 2019-12-01 09:41:09
题面 对于每个点建立一颗主席树; 然后按照树上差分的思想统计主席树的前缀和; lca+主席树+前向星存表就可以了; #include <bits/stdc++.h> #define inc(i,a,b) for(register int i=a;i<=b;i++) #define dec(i,a,b) for(register int i=a;i>=b;i--) using namespace std; int head[2000010],cnt; class littlestar{ public: int to; int nxt; }star[2000010]; void add(int u,int v){ star[++cnt].to=v; star[cnt].nxt=head[u]; head[u]=cnt; } int n,m; template<class nT> inline void read(nT& x) { char c; while(c=getchar(),!isdigit(c)); x=c^48; while(c=getchar(),isdigit(c)) x=x*10+c-48; } int a[2000010],val[2000010]; int dep[2000010],f[1000010][30]; void pre(int u,int fa) { /

主席树 hdu 4348

送分小仙女□ 提交于 2019-12-01 07:16:09
题意:有一个由n个数组成的序列,有4中操作: 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时间,且下一秒的时间从t开始 按时间建立主席树,主席树上的每一棵线段树维护[1,n]这段序列的信息,这里成段更新的时候要注意,以往写线段树的时候,都是把lazy标记向下传,但是写主席树的时候每一次下传,那么新的节点数就会非常多,会爆内存,所以我们不把lazy操作下传,只是在询问的时候,最后累加的答案加上每一个父亲节点上的lazy值。 1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<iostream> 5 using namespace std; 6 typedef long long ll; 7 const int maxn=1e5+10; 8 ll a[maxn]; 9 int root[maxn]; 10 struct node 11 { 12 int ln,rn; 13 ll lazy,sum; 14 }tree[maxn*30]; int cnt; 15 void build(int &x,int l,int r) 16 { 17 ++cnt;x=cnt; 18 tree[x]

[CSP-S模拟测试]:e(树上主席树)

北慕城南 提交于 2019-12-01 05:31:12
题目传送门(内部题66) 输入格式 第一行,一个正整数$n$,一个自然数$q$,一个整数$type$。 第二行,$n$个正整数,代表$a_i$。 接下来$n-1$行,每行两个正整数$u$、$v$,代表树中存在一条边$(u,v)$。 接下来$q$行,每行两个正整数$r$、$k$,然后$k$个正整数$x_1,x_2,...,x_k$。询问中的$p_i=(x_i−1+lastans\times type)\mod n+1$。$lastans$为上一个询问的答案,一开始$lastans=0$。 输出格式 输出$q$行,每行一个自然数,代表对应询问的答案。 输出格式 输出$q$行,每行一个自然数,代表对应询问的答案。 样例 样例输入: 5 7 0 1 2 3 4 5 1 2 2 3 2 4 1 5 1 2 4 5 2 2 4 5 3 2 4 5 4 2 4 5 5 2 4 5 5 1 2 100 3 1 2 5 样例输出: 0 0 1 0 0 3 95 数据范围与提示 保证$type\in \{0,1\},1\leqslant a_i,r\leqslant 10^9,u,v,x_i\in [1,n]$。 题解 可以说是一道树上主席树的板子题(然而当时并不会……)。 显然集合$S$就是所有$p_k$到所有$p_k$的$LCA$之间的所有点。 与普通主席树的区别在于,普通主席树维护的是序列

主席树

ぐ巨炮叔叔 提交于 2019-12-01 02:34:13
主席树:k-thnumber 入门 https://www.bilibili.com/video/av4619406/?p=2 https://blog.csdn.net/woshinannan741/article/details/53012682 #include<cstdio> #include<cmath> #include<algorithm> #include<vector> using namespace std; const int maxn=1e5+6; int n,m,cnt,root[maxn],a[maxn],x,y,k; struct node{int l,r,sum;}T[maxn*40]; vector<int>v; int getid(int x){return lower_bound(v.begin(),v.end(),x)-v.begin()+1;} void update(int l,int r,int &x,int y,int pos) { T[++cnt]=T[y],T[cnt].sum++,x=cnt; if(l==r) return ; int mid=(l+r)/2; if(mid>=pos) update(l,mid,T[x].l,T[y].l,pos); else update(mid+1,r,T[x].r,T[y].r,pos)

主席树 模板题 luogu([POI2014]KUR-Couriers)

╄→尐↘猪︶ㄣ 提交于 2019-11-30 23:36:47
求区间内是否有个数大于二分之一的数,有的话输出这个数,没有的话输出0. 在询问的时候,如果左边有sum大于这个limit,就可以继续求,如果右边有sum大于limit 也递归, 如果都不行,返回 0; 1 #include<cstdio> 2 #include<algorithm> 3 #include<string.h> 4 #include<math.h> 5 using namespace std; 6 const int maxn=5e5+10; 7 int Root[maxn],cnt; 8 struct node 9 { 10 int ln,rn,sum; 11 }tree[maxn*20]; 12 void add(int &x,int y,int l,int r,int num) 13 { 14 tree[++cnt]=tree[y];tree[cnt].sum++;x=cnt; 15 if(l==r) return; 16 int mid=l+r>>1; 17 if(num<=mid) add(tree[x].ln,tree[y].ln,l,mid,num); 18 else add(tree[x].rn,tree[y].rn,mid+1,r,num); 19 } 20 int query(int x,int y,int l,int r,int limit) 21

hdu-6230 主席树/树状数组+离线

我的未来我决定 提交于 2019-11-30 16:05:00
  刚开始是听说了要用manacher采取写的,但是不难看出要使用manacher,因为题目要求的1个半回文串,其实就是两个回文中心的交集,你要找两个回文中心,让它们的回文半径可以互相覆盖即可。问题转化成了对于一个回文中心,它覆盖的左侧的所有回文中心中( 向右覆盖的范围超过i )这样的点的数量。这样就变成了求区间中大于x的数的个数,可以用主席树解决。 #include<iostream> #include<cstring> #include <string> #include<algorithm> using namespace std; typedef long long ll; const int maxn=1e6+20; const int maxm=2e7+20; char s[maxn],s_new[maxn]; int p[maxn]; int init() { int len=(int)strlen(s); s_new[0]='$'; s_new[1]='#'; int j=2; for(int i=0;i<len;i++) { s_new[j++]=s[i]; s_new[j++]='#'; } s_new[j]=0; return j; } int manacher() { int len=init(); int id=0,mx=0; for(int i=1;i