线段树的复杂操作

一,线段树做区间乘法

首先要明白,乘法操作高于加法操作

一般的话会开long long ,要去模

对于一个节点o,我们设区间和为sum[o],加法标记为add[o],乘法标记为mul[o]

mul标记的初始值是1,add标记初始值是0 
在修改值的时候,add的维护需要累加,mul的维护需要累乘

此时当我们进行区间加的时候,一切照旧

但是当进行区间乘法的时候

儿子节点的add标记分别先乘上父亲节点的乘标记再加上父亲节点的加标记 
(因为父亲节点的加标记已经乘上了一些乘标记了,不需要再乘一次)

儿子节点的乘标记直接乘上父亲节点的乘标记。

 1 void Mul(ll o,ll l,ll r,ll x,ll y,ll k)
 2 {
 3     if(x<=l && y>=r)
 4     {
 5         add[o]=add[o]%mod*k%mod;//相当于加了k个add[o]
 6         sum[o]=sum[o]*k%mod%mod;
 7         mul[o]=mul[o]*k%mod;
 8         return;
 9     }
10     ll mid=(l+r)>>1;
11     down(o,l,r,mid);
12     if(x<=mid) Mul(o<<1,l,mid,x,y,k);
13     if(y>=mid+1) Mul(o<<1|1,mid+1,r,x,y,k);
14     sum[o]=(sum[o<<1]+sum[o<<1|1])%mod;
15 }

所以标记下放的时候

 1 void down(ll o,ll l,ll r,ll mid)
 2 {
 3     if(add[o]==0 && mul[o]==1) return;
 4     add[o<<1]=(add[o<<1]*mul[o]+add[o])%mod;
 5     mul[o<<1]=mul[o<<1]*mul[o]%mod;
 6     sum[o<<1]=(sum[o<<1]*mul[o]%mod+add[o]*(mid-l+1)%mod)%mod;
 7
 8     add[o<<1|1]=(add[o<<1|1]*mul[o]+add[o])%mod;
 9     mul[o<<1|1]=mul[o<<1|1]*mul[o]%mod;
10     sum[o<<1|1]=(sum[o<<1|1]*mul[o]+add[o]*(r-(mid+1)+1))%mod;
11
12     add[o]=0;mul[o]=1;
13 }

二,区间除法,开方操作

除法,开方的操作会让各个数字之间越来越相近,最后变成一串一串连续的数字都是一样的,所以对于这一部分的操作我们一定程度上使用暴力,而如果一段都相等就相当于直接进行区间减法的操作
(对于单个点或者区间内的数完全相同的区间,可以做成区间减法
因为除法会使数变小,而相同的数减小的量是相同的)
那么我们来看如何判断区间一段都相等,那我们只需要维护区间的最值,最小值==最大值就完全相等了
1除法不能打lazy而是更新到底,复杂度可以保证(log级别),因为很快降到0
然后
暴力一波

代码,见相关的题解,我的

原文地址:https://www.cnblogs.com/adelalove/p/11779177.html

时间: 2024-10-12 18:12:39

线段树的复杂操作的相关文章

线段树区间更新操作及Lazy思想(详解)

此题题意很好懂:  给你N个数,Q个操作,操作有两种,‘Q a b ’是询问a~b这段数的和,‘C a b c’是把a~b这段数都加上c. 需要用到线段树的,update:成段增减,query:区间求和 介绍Lazy思想:lazy-tag思想,记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率. 在此通俗的解释我理解的Lazy意思,比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果

UVa 11992 Fast Matrix Operations(线段树双懒操作,二维转一维)

题意:给个r*c的矩形,三种操作,将一个子矩形权值+v,将一个子矩阵权值赋值为v,查询一个子矩阵sum,max,min.起初矩阵权值为0,保证r<=20,r*c<=1e6,操作次数不超过10000 链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18697 题解:将二维转一维,设当前点为(x,y),则它在线段树上的点为(x-1)*c+y,由于行不超过20行,不妨枚举每一行,去操作.对于一维的线段树,要进行赋值,加法

poj 3667 Hotel (线段树的合并操作)

Hotel The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a vacation on the sunny shores of Lake Superior. Bessie, ever the competent travel agent, has named the Bullmoose Hotel on famed Cumberland Street as t

CodeForces 620E New Year Tree(线段树的骚操作第二弹)

The New Year holidays are over, but Resha doesn't want to throw away the New Year tree. He invited his best friends Kerim and Gural to help him to redecorate the New Year tree. The New Year tree is an undirected tree with n vertices and root in the v

线段树- 算法训练 操作格子

问题描述 有n个格子,从左到右放成一排,编号为1-n. 共有m次操作,有3种操作类型: 1.修改一个格子的权值, 2.求连续一段格子权值和, 3.求连续一段格子的最大值. 对于每个2.3操作输出你所求出的结果. 输入格式 第一行2个整数n,m. 接下来一行n个整数表示n个格子的初始权值. 接下来m行,每行3个整数p,x,y,p表示操作类型,p=1时表示修改格子x的权值为y,p=2时表示求区间[x,y]内格子权值和,p=3时表示求区间[x,y]内格子最大的权值. 输出格式 有若干行,行数等于p=2

1.1 线段树的基础操作

本篇对应的是luogu的线段树1 概况: 如下图就是一棵线段树,线段树上的每一个点记录的都是一个区间,所以线段树支持对于区间和点的动态操作,可以在线查询和更改区间上的最值,求和等 时间复杂度:O(n) 使用线段树的情况: 满足区间加法:已知左右两子树的全部信息,一定能够推出父节点 线段树维护的内容根据题目的要求而定 线段树的分类: 根据题目中对于查询和修改区间的不同要求,大致将线段树分为三类: problem1:单点修改,单点查询 problem2:区间修改,单点查询 problem3:区间修改

山海经 (线段树高阶操作)

前几天看mike的ppt发现有线段树的题,就挑了第一道题搞搞吧,然后就gg了,花了三天时间总算搞掉了 先放题: 775. 山海经 ★★★☆   输入文件:hill.in   输出文件:hill.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] “南山之首日鹊山.其首日招摇之山,临于西海之上,多桂,多金玉.有草焉,其状如韭而青华,其名日祝余,食之不饥……又东三百里,日堂庭之山,多棪木,多白猿,多水玉,多黄金. 又东三百八十里,日猨翼之山,其中多怪兽,水多怪鱼,多白玉,

Sequence operation(线段树区间多种操作)

Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 7452    Accepted Submission(s): 2220 Problem Description lxhgww got a sequence contains n characters which are all '0's or '1

BZOJ 4034 树上操作(树的欧拉序列+线段树)

刷个清新的数据结构题爽一爽? 题意: 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 注意到操作3,询问x到根的路径之间点权和,容易发现这就是欧拉序列中的前缀和. 所以按照树的欧拉序列建线段树,然后操作1就变成单点修改,操作2,就变成了区间内某些点+a,某些点-a,也容易用tag标记