线段树

[HEOI2016/TJOI2016]树

≡放荡痞女 提交于 2019-12-04 04:38:46
题目概述 题目描述 在 2016 年,佳媛姐姐刚刚学习了树,非常开心。 现在他想解决这样一个问题:给定一颗有根树,根为 \(1\) ,有以下两种操作: 标记操作:对某个结点打上标记。(在最开始,只有结点 \(1\) 有标记,其他结点均无标记,而且对于某个结点,可以打多次标记。) 询问操作:询问某个结点最近的一个打了标记的祖先。(这个结点本身也算自己的祖先) 你能帮帮她吗? 输入输出格式 输入格式 第一行两个正整数 \(N\) 和 \(Q\) 分别表示节点个数和操作次数。 接下来 \(N-1\) 行,每行两个正整数 \(u,v \,\, (1 \leqslant u,v \leqslant n)\) 表示 \(u\) 到 \(v\) 有一条有向边。 接下来 \(Q\) 行,形如 oper num , oper 为 C 时表示这是一个标记操作, oper 为 Q 时表示这是一个询问操作。 输出格式 输出一个正整数,表示结果 输入输出样例 输入样例 #1 5 5 1 2 1 3 2 4 2 5 Q 2 C 2 Q 2 Q 5 Q 3 输出样例 #1 1 2 2 1 数据范围 \(30\%\) 的数据, \(1 \leqslant N, Q \leqslant 1000\) ; \(70\%\) 的数据, \(1 \leqslant N, Q \leqslant 10000\) ; \

技巧

北战南征 提交于 2019-12-04 04:01:19
生成匹配的括号序列,只需模拟一个栈,记录栈中的括号数即可(CF1015F,CF508E)。 AC自动机算法在匹配时,在fail树上的链将都被匹配,所以经常与树上算法联合使用(luogu P3796,luogu P2336喵星球上的点名)。 平面图的最小割就是对偶图的最短路(每个面看做一个点,相邻的面看做边)(luogu P2046海拔,luogu 狼抓兔子)。 求第k小值(k不大),可以采用A*算法,要保证每种状态都能被扩展出,且扩展出的状态非递减(luogu 超级钢琴,K短路,OVOO)。 互质数的选择,当质因数较大时采用分组背包,较小时状压记录,以平方根为界(luogu寿司晚宴)。 有时,权值线段树可以代替treap,能减小常数和代码量(luogu 郁闷的出纳员)。 有时,线段树可以代替splay,方法时记录每个位置是否有元素,查询第k个值时线段树上二分(NOIP2017 列队)。 在一棵树上统计子树信息,如果子树信息不能快速合并,可以采用dsu on tree算法(luogu 雨天的尾巴,回文路径计数)。 对于状态转移有环的动态规划,使用如下方式求解: 若转移里没有max/min,只有加减乘除运算,可以建立方程组,通过高斯消元在O(n^3)得出解。 若转移只是对一些元素取max/min(或第k大/小值),再加/减一个值,可以建图,使用dij或spfa求解。 若u依赖v

P5025 [SNOI2017]炸弹 题解

≯℡__Kan透↙ 提交于 2019-12-04 03:38:05
蒟蒻的第一篇黑题题解(学了这么长时间了才第一道也是没谁了。) 题目链接 ; Solution : 朴素:  根据题目描述,我们可以处理每一个x节点左右爆炸半径范围内的点,然后模拟一次爆炸 (for),遍历每一个点。每当我们遍历到一个点,我们就对这个点在进行一次处理半径+dfs直到没有能遍历的了,直接统计遍历的点数然后输出。 时间复杂度:O(n^2)级别。 于是乎:    是不是可以暴力踩标算了呢? 显然完全接受不了。 因为这个算法要考虑到连边操作。对于每一个点,我们要将它自己连向能够遍历到的边,那么意味着,一个边要被连很多次。 就如下图: 其中编号为1的节点能炸到1 2 3 4 5,2能炸到1 2 3,3能炸到1 2 3 4 5,其中2 3 4挺惨的。 于是有了这么一个线段树建图的思路: 考虑线段树的性质,上层节点可以代表下层节点的一段区间,那么我们是不是也可以建这类的上层边,表示通过这条边能遍历到它对应的下层边的所有点 。 (就是这句精华) 这样我们先把所有点进行从1到n的编号,然后跑线段树的build建边,然后依次对每一个点进行从底层(只能这么理解)到上层节点的连边表示能遍历到上层节点能遍历到的节点。 这样的话,会形成很多环。在对每一个点都进行范围连边以后,对于一个环(或者强连通分量)内的点,自然能互相遍历到,为了方便统计

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

耗尽温柔 提交于 2019-12-04 02:23:07
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e5+10; 4 int a[maxn]; 5 int sum[maxn<<2],exc[maxn<<2]; 6 void maintain(int k) 7 { 8 sum[k]=sum[k<<1]+sum[k<<1|1]; 9 } 10 void pushdown(int lenl,int lenr,int k)//标记下放,并更细节点信息 11 { 12 if(exc[k]){ 13 exc[k<<1]=exc[k]; 14 exc[k<<1|1]=exc[k]; 15 sum[k<<1]=exc[k]*lenl; 16 sum[k<<1|1]=exc[k]*lenr; 17 exc[k]=0; 18 } 19 } 20 void build(int l,int r,int k) 21 { 22 if(l>r) 23 return ; 24 if(l==r){ 25 sum[k]=a[l]; 26 exc[k]=0; 27 return ; 28 } 29 int mid=(l+r)>>1; 30 build(l,mid,k<<1); 31 build(mid+1,r,k<<1|1); 32 maintain(k); 33 } 34 void

线段树算法(未完成)

巧了我就是萌 提交于 2019-12-04 02:12:16
1 struct node 2 { 3 int l,r,sum; 4 }; 5 node no[500000]; 6 //存放每个点的值 7 int number[50000]; 8 //存放每个点对应的节点 9 int pa[500000]; 10 void build(int k,int l,int r) 11 { 12 no[k].l=l; 13 no[k].r=r; 14 if(l==r) 15 { 16 no[k].sum=number[l]; 17 pa[l]=k; 18 return ; 19 } 20 int mid=(l+r)/2; 21 build(k*2,l,mid); 22 build(k*2+1,mid+1,r); 23 no[k].sum=no[k*2].sum+no[k*2+1].sum; 24 } 25 void change(int k,int x) 26 { 27 no[k].sum +=x; 28 if(k!=1) 29 { 30 change(k/2,x); 31 } 32 } 33 int query(int k,int l,int r) 34 { 35 if(no[k].l==l&&no[k].r==r) 36 { 37 return no[k].sum; 38 } 39 int mid = (no[k].l+no[k].r)/2; 40

[模板]正常线段树

╄→尐↘猪︶ㄣ 提交于 2019-12-04 01:26:30
    [模板]正常线段树   RT    1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 #define int long long 6 #define maxn 400050 7 int n,m,ans=0; 8 int a[100050]; 9 struct node 10 { 11 int l; 12 int r; 13 int w; 14 int f; 15 }tree[maxn]; 16 17 void build(int k,int l,int r) 18 { 19 tree[k].l=l; 20 tree[k].r=r; 21 if(l==r) 22 { 23 tree[k].w=a[l]; 24 return ; 25 } 26 int mid=(l+r)>>1; 27 build(k<<1,l,mid); 28 build(k<<1|1,mid+1,r); 29 tree[k].w=tree[k<<1].w+tree[k<<1|1].w; 30 } 31 void down(int k) 32 { 33 if(tree[k].w) 34 { 35 tree[k<<1].w+=tree[k].f*(tree[k<<1].r-tree[k<

线段树

放肆的年华 提交于 2019-12-04 00:39:35
统计区间数字个数 #include<bits/stdc++.h> using namespace std; #define CL(a,b) memset(a,b,sizeof(a))//简化代码 #define MAXN 100010 struct node { int l,r,s; } t[MAXN<<2]; int L,O,T; int sum[33];//因为颜色数不多,可以用一个数组来装;1表示该区间有该颜色,0反之 void build(int l, int r, int i) { t[i].l = l; t[i].r = r; t[i].s = 1; if(l == r) return ; int mid = (l+r)>>1; build(l, mid, i<<1); build(mid+1, r, i<<1|1); } void update(int l, int r, int m, int i) { if(t[i].s == m) return ; if(t[i].l == l && t[i].r == r) { t[i].s = m; return ; } if(t[i].s != -1) { t[i<<1].s = t[i<<1|1].s = t[i].s; t[i].s = -1; } int mid = (t[i].l+t[i].r)>>1; if(l >

线段树复习

笑着哭i 提交于 2019-12-03 23:36:36
P2572 [SCOI2010]序列操作 这道题题解已经很多了 但是我还是想写一篇 纪念 调三天代码 思路 思路 很简单 struct node { int len,sum,lazy,rev,lsum[2],rsum[2],maxl[2]; }tree[MAXN << 2]; len:长度 sum:1的个数 lazy:把[a, b]区间内的所有数全变成0/1标记 rev:反转标记 lsum[1/0]:记录从左边开始的最长连续1/0的个数 rsum[1/0]:记录从右边开始的最长连续1/0的个数 maxl[1/0]:记录区间内最长连续1/0的个数 然后 就正常的线段树操作了 主要是调试 调试要点 来说一些技巧 \(pushdown\) 时 要么左区间,要么右区间 可以考虑 两次 \(pushdown\) 每次传 现在区间标号 修改区间标号 修改区间长度 pushdown(k,k << 1,mid - l + 1); pushdown(k,k << 1 | 1,r - mid); r - mid !!不要+1!! 类似的 update(k,k << 1,k << 1 | 1,mid - l + 1,r - mid,0); 修改lsum[0],rsum[0],maxl[0] update(k,k << 1,k << 1 | 1,mid - l + 1,r - mid,1); 修改lsum

【牛客】排列计数机(线段树 二项式定理)

走远了吗. 提交于 2019-12-03 22:29:56
题目描述 定义一个长为k的序列A1,A2,…,Ak的权值为:对于所有1≤i≤k,max⁡(A1,A2,…,Ai)有多少种不同的取值。 给出一个1到n的排列B1,B2,…,Bn,求B的所有非空子序列的权值的m次方之和。 答案对10 9 +7取模。 输入描述 第一行两个整数n、m。 接下来一行n个整数,第i个整数为Bi。 输出描述 输出一个整数,表示答案。 示例1 输入 3 2 1 3 2 输出 16 说明 在所有非空子序列中: (1), (3), (2), (3, 2)权值为1, (1, 3), (1, 2), (1, 3, 2)权值为2。 那么所有非空子序列权值的2次方和为4×1 2 +3×2 2 =16。 备注: 对于前10%的数据,n≤20。 对于前20%的数据,n≤100。 对于前40%的数据,n≤1000。 对于另外20%的数据,m=1。 对于所有数据,1≤n≤10 5 ,1≤m≤20,保证B是1到n的排列。 分析 直接求看样子是不可能的 ,出题人这辈子都不可能让你直接求的 所以考虑从左到右一个一个加入数。 当加入一个数的时候,只有最大值小于这个数的子序列,权值才会被更新(即加1) 我们不可能把每个子序列的权值都求出来后才乘方再加起来,铁定会T 但我们根据二项式定理,可以发现对于任意一个数x $$(x+1)^m=C_{m}^{0}x^{m}+C_{m}^{1}x^{m-1}

【BZOJ2138】stone(线段树+hall定理)

强颜欢笑 提交于 2019-12-03 21:13:43
传送门 题意: 现在有 \(n\) 堆石子,每堆石子有 \(a_i\) 个。 之后会有 \(m\) 次,每次选择 \([l,r]\) 的石子堆中的石子扔 \(k\) 个,若不足,则尽量扔。 现在输出 \(1\) ~ \(m\) 次,每次最多能取到多少石子(输出第 \(i\) 次的情况时,要考虑前 \(i-1\) 次)。 给出的区间不存在包含关系。 思路: 稍微暴力点想就是一个二分图,将 \(k_i\) 拆在左边,然后石子在右边,每次最大匹配。 但这做法显然不可行,时间复杂度不能承受。 这种一般就考虑 \(hall\) 定理:假设前面都满足的情况下,如果现在新加进来一段区间,假设我们取走 \(k\) 个石子,那么就是现在要满足最大匹配,因为也不能影响前面取的,那么现在所有包含 \([l,r]\) 的区间都要满足:取石子的量不超过石子个数。 这理解了这个题基本就做出来了,接下来就是维护信息。 定义 \(a_i:\) 右端点不超过 \(i\) 的所有区间的需求量; 定义 \(b_i:\) 左端点不超过 \(i\) 的所有区间的需求量; 定义 \(s_i:1\) ~ \(i\) 堆石子的个数和。 那么一段区间的需求量即为: \(a_r-b_{l-1}\) 。 将上面说的一大段话形式化就有: 对于所有的 \(l < r:a_r-b_{l-1}\leq s_r-s_{l-1}\) ,移项: \