线段树

codeforces 600E 线段树合并

≯℡__Kan透↙ 提交于 2019-11-28 00:25:05
  题意:给你一棵有 n n 个点的树 (n\leq10^5) ( n ≤ 1 0 5 ) ,树上每个节点都有一种颜色 ci(ci\leq n) c i ( c i ≤ n ) ,让你求每个点子树出现最多的颜色的 颜色编号 的和 权值线段维护一下出现最多的数字即可 #include<bits/stdc++.h> using namespace std; #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define ll long long #define see(x) (cerr<<(#x)<<'='<<(x)<<endl) #define inf 0x3f3f3f3f #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// const int N=2e6+10; ll sum[N<<2],t[N<<2],anss[N]; int lson[N<<2],rson[N<<2],ncnt,pos,head[N],c[N],n,T[N]; void up(int pos) { if(sum[lson[pos]]>sum[rson[pos]]) { sum[pos]

[leetcode 周赛 149] 1157 子数组中占绝大多数的元素

て烟熏妆下的殇ゞ 提交于 2019-11-28 00:01:18
目录 1157 Online Majority Element In Subarray 子数组中占绝大多数的元素 描述 思路 代码实现 1157 Online Majority Element In Subarray 子数组中占绝大多数的元素 描述 实现一个 MajorityChecker 的类,它应该具有下述几个 API : MajorityChecker(int[] arr) 会用给定的数组 arr 来构造一个 MajorityChecker 的实例。 int query(int left, int right, int threshold) 有这么几个参数: 0 <= left <= right < arr.length 表示数组 arr 的子数组的长度。 2 * threshold > right - left + 1 ,也就是说阈值 threshold 始终比子序列长度的一半还要大。 每次查询 query(...) 会返回在 arr[left] , arr[left+1] , ..., arr[right] 中至少出现阈值次数 threshold 的元素,如果不存在这样的元素,就返回 -1 。 示例: MajorityChecker majorityChecker = new MajorityChecker([1,1,2,2,1,1]); majorityChecker

数据结构小结

会有一股神秘感。 提交于 2019-11-27 23:53:43
并查集 普通的并查集没有什么好说的,对于遇到的题目,我们主要是要把它抽象成并查集的模型,比如 萌萌哒 这道题就是一个对于模型的抽象,相同的标记其实就是一个并查集。 然后想说一下并查集的两种合并,一种是路径压缩,一种是按秩合并。 按秩合并更多是对于可撤销并查集 (还没打过板子) 和 可持久化并查集 然后个人觉得有一个很重要的思想就是镜像点思想,关押罪犯和 Uva 11987 都是这种思想 带权并查集目前只见过搬砖(bricks)那道题。 线段树 基操没有什么好说的了 线段树主要是用来维护区间信息,是一个很好的工具。 也常常用来优化时间。(比如 线段树优化dp ) 打标记 //为什么在Pushdown中更新下面的总值的时候为什么不把要更新的点的Pass也加进去, //是因为在modify的时候我已经用他原来的Pass值更新过一遍了,当然不需要加进去 //即:标记下传给左右儿子时答案(比如sum)是用k的来更新,而不是k<<1和k<<1|1 加标记和乘标记 加标记:打上就行 乘标记:加标记乘上这个值,乘标记打上 pushdown: 先乘再加 加标记和赋值标记 加标记:打上就行 赋值标记:加标记去掉,打上赋值标记 pushdown: 先放赋值标记,再放加标记 翻转标记 多是在splay上面打。 但翻转标记和赋值标记加标记不冲突。 打标记基础题 戳 打标记妙题 戳 树链剖分 也是一个工具

BZOJ4239(线段树)

拟墨画扇 提交于 2019-11-27 23:51:26
一道权限题 题面 描述 农夫Byteasar买了一片n亩的土地,他要在这上面种草。 他在每一亩土地上都种植了一种独一无二的草,其中,第i亩土地的草每天会长高a[i]厘米。 Byteasar一共会进行m次收割,其中第i次收割在第d[i]天,并把所有高度大于等于b[i]的部分全部割去。Byteasar想知道,每次收割得到的草的高度总和是多少,你能帮帮他吗? Input 第一行包含两个正整数n,m(1<=n,m<=500000),分别表示亩数和收割次数。 第二行包含n个正整数,其中第i个数为ai,依次表示每亩种植的草的生长能力。 接下来m行,每行包含两个正整数d[i],bi,依次描述每次收割。 数据保证d[1] < d[2] <… < d[m],并且任何时刻没有任何一亩草的高度超过10^12。 Output 输出m行,每行一个整数,依次回答每次收割能得到的草的高度总和。 样例输入 4 4 1 2 4 3 1 1 2 2 3 0 4 4 样例输出 6 6 18 0 思想是比较奇妙的。 仔细读题,我们发现草的高度成一个单调性(因为每株草每天的生长量是一定的),考虑把草sort排序,那么每次先找到第一个大于b的草,从它开始后面的草都要被割 维护这样一些信息: day:从上一次收割到这一次过去的天数 now:当前草的高度(每一次割草后那一串的草的高度都是b,那么对应区间now为b) ans

线段树区间修改及查询区间和

只愿长相守 提交于 2019-11-27 22:04:12
void update(int p) { if(t[p].add) { t[p*2].sum+=(t[p*2].r-t[p*2].l+1)*t[p].add; t[p*2+1].sum+=(t[p*2+1].r-t[p*2+1].l+1)*t[p].add; t[p*2].add+=t[p].add; t[p*2+1].add+=t[p].add; t[p].add=0; } } void change(int p,int l,int r,int d) { if(l<=t[p].l&&r>=t[p].r) { t[p].sum+=(t[p].r-t[p].l+1)*d; t[p].add+=d; return; } update(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid) change(p*2,l,r,d); if(r>mid) change(p*2+1,l,r,d); t[p].sum=t[p*2].sum+t[p*2+1].sum; } void build(int p,int l,int r) { t[p].l=l,t[p].r=r;t[p].sum=0,t[p].add=0; if(l==r) { t[p].sum=t[p].add=0; return; } int mid=(l+r)/2; build(p*2,l,mid);

线段树总结

荒凉一梦 提交于 2019-11-27 21:47:05
高级数据结构——线段树 总结 本蒟蒻最近在做线段树的题,做了一小部分,有感而发,故写下这篇博客,如有错误,请大佬指出。 线段树,作为一种高级数据结构,而其作用与分块、树状数组均有一脉相承的部分,而且有的题均可以使用上面的两种算法去解决(当然只是一部分题) 对于线段树的介绍,我也就不再多说了,即对于数列将其放在树上进行维护一些值,在题目的要求下进行修改和更新,最后得到答案。 首先我们先上一两道模板题 1、 洛谷P3372线段树1(加操作) 这是一道十分经典的线段树模板, 当然他的解法也有其他方法, (十分重要)。 下面是代码: #include<bits/stdc++.h> #define ll long long const int N=5e6+8; using namespace std; ll n,m,tag[N],ans[N],a[N]; ll ls(ll x){ return x<<1; }//左儿子扩展 (x*2) ll rs(ll x){ return x<<1|1; }//右儿子扩展(x*2+1) void up(ll x){ ans[x]=ans[ls(x)]+ans[rs(x)]; }// 求出当前点的总和值 void build(ll l,ll r,ll p){ if(l==r){ ans[p]=a[l]; return; } ll mid=(l+r)>>1;

mex(线段树+离散化)

て烟熏妆下的殇ゞ 提交于 2019-11-27 21:43:28
题目描述: 给你一个无限长的数组,初始的时候都为0,有3种操作: 操作1是把给定区间 [ l , r ] [l,r] 设为1, 操作2是把给定区间 [ l , r ] [l,r] 设为0, 操作3把给定区间 [ l , r ] [l,r] 0,1反转。 一共n个操作,每次操作后要输出最小位置的0。 题解: 经过分析观察,可以发现,答案只有可能是 1 , l , r + 1 所以我们开一个数组记录1,以及所有的l,r,r+1,并离散化 然后用线段树模拟操作即可 这里有两种思路: 一种是记录某一区间内0的最小位置和1的最小位置,反转时互换两个位置 #include<iostream> #include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N=1e5+5; const int maxn=3e5+5; int n,m;ll a[maxn]; struct que{ int op;ll l,r; }q[N]; int s0[maxn<<2],s1[maxn<<2],lazy[maxn<<2],rev[maxn<<2]; void pushup(int u){ if(s0[u*2]) s0[u]=s0[u*2]; else if(s0[u*2+1]) s0[u]=s0

ZROI 19.08.06模拟赛

一笑奈何 提交于 2019-11-27 20:31:08
传送门 写在前面:为了保护正睿题目版权,这里不放题面,只写题解。 今天正睿又倒闭了,从删库到跑路。 天祺鸽鸽txdy! A “不要像个小学生一样一分钟就上来问东西。”——蔡老板 虽然配图确实很有迷惑性。 所以读题不仔细,爆零两行泪。 “这题也就NOIP第二题难度吧。”——R爷 \(30pts:\) 显然的暴力, 读懂题意之后 \(O(w\times h)\) 模拟即可。 \(100pts:\) 每根短棍的效果在于交换相邻数。所以最后一定仍是个排列。 可以默认每个位置都要交换,拆掉某根短棍就等价于换回来。 从某个位置出发,只看位置不看标号,球的轨迹是确定的,可以每次修改时 \(O(1)\) 算。 交换时只换标号,找标号时只按出发时的位置考虑。 代码很短,然而 \(7\) 行的东西我写+拍了 \(2.5h\) ,菜死了。 标算是treap, 那我岂不是把标算踩了 R爷的考场策略: \(15\min\) 内写完treap,调试 \(15\min\) ,大概半小时就能过掉了。R爷nb! B \(100pts:\) 显然答案为 \(2^x\) ,其中 \(x\) 为两个人路径分开的段数。 发现两个人的路径是等长的,可以让两个人同步行动。 对于两个人的路径重合的部分可以简单判断。 否则不妨设 \(y_1<y_2\) ,即第一个人在第二个人上面。 显然第二个人上面的区块是不会被第二个人走到的

ZROI 19.07.28 序列数据结构/jk

喜你入骨 提交于 2019-11-27 20:30:42
写在前面 dls:“我不会数据结构,但是APIO的数据结构场我写了,还是蛮简单的。” T1 CF643G Sol: 有一个 \(O(n\log^2n)\) 的做法:假设将区间排好序,取六等分点,则答案一定覆盖了若干点,求区间第 \(k\) 大即可。 然而会TLE 定义绝对众数为区间中出现超过一半的数。 有一个经典的做法求绝对众数,然而它要在保证有解的时候才保证正确性。 维护当前答案和出现次数,遇到相同则 \(+1\) ,不同则 \(-1\) ,降为 \(-1\) 的时候就把当前解替换。 显然如果有解的话,答案不会被替换掉(或者最后会换回来)。 可以扩展到 \(p\not= \frac{1}{2}\) 的情况,维护多个答案,调整加减权重即可。 可以用线段树维护上述操作。 顺便一提dls讲题的时候翻车了23333 (被打死 线段树合并两个儿子的时候,先执行替换,再全部 \(-1\) 。正确性dls也 不会 不屑于证。 T2 HDU6087 Sol: 不会可持久化平衡树,告辞。 T4 CF453E Sol: 序列可以分成若干段,每段都是同一时间清空的。 显然段的总数 \(O(n)\) 。 以按恢复满需要的时间为权建主席树,因为同一段恢复的时间是相同的,一次查询一整段,可以 \(O(n\log n)\) 做。 T5 CF1172F Sol: 发现每个位置都是一个分段函数。

线段树总结

元气小坏坏 提交于 2019-11-27 19:17:05
高级数据结构——线段树 总结 本蒟蒻最近在做线段树的题,做了一小部分,有感而发,故写下这篇博客,如有错误,请大佬指出。 线段树,作为一种高级数据结构,而其作用与分块、树状数组均有一脉相承的部分,而且有的题均可以使用上面的两种算法去解决(当然只是一部分题) 对于线段树的介绍,我也就不再多说了,即对于数列将其放在树上进行维护一些值,在题目的要求下进行修改和更新,最后得到答案。 首先我们先上一两道模板题 1、 洛谷P3372线段树1(加操作) 这是一道十分经典的线段树模板, 当然他的解法也有其他方法, (十分重要)。 下面是代码: #include<bits/stdc++.h> #define ll long long const int N=5e6+8; using namespace std; ll n,m,tag[N],ans[N],a[N]; ll ls(ll x){ return x<<1; }//左儿子扩展 (x*2) ll rs(ll x){ return x<<1|1; }//右儿子扩展(x*2+1) void up(ll x){ ans[x]=ans[ls(x)]+ans[rs(x)]; }// 求出当前点的总和值 void build(ll l,ll r,ll p){ if(l==r){ ans[p]=a[l]; return; } ll mid=(l+r)>>1;