1. 程式人生 > >淺談線段樹中加與乘標記的下放

淺談線段樹中加與乘標記的下放

感覺題解裡面對加和乘標記下放的順序講的不是很清楚,要麼是直接沒說,要麼是一句話帶過

如果想看1080P高清無碼證明的可以報洛谷冬令營省選班,去看第一天的回放233

假設我們一個節點為\([val,mul,add]\),其中\(val\)代表該節點的權值,\(mul\)為乘法標記,\(add\)為加法標記

那麼我們有兩種表示方式,

  • 第一種:先加再乘

此時該節點為\((val+add)*mul\)

當再遇到一個\([\_mul,\_add]\)的標記時,

此時節點為\([(val+add)*mul+\_add]*\_mul\)

把式子展開並重新化為\((val+add')*mul'\)的形式
(也就是提出\(mul*\_mul\)

這一項)得

\((val+add+\frac{\_add}{mul})*mul*\_mul\)

我們發現這裡有個除法,會損失很多精度

因此我們換一個思路

  • 第二種:先乘再加

此時該節點為\((val*mul)+add\)

當再遇到一個\([\_mul,\_add]\)的標記時,

此時節點為\([(val*mul)+add]*\_mul+\_add\)

把式子展開並重新化為\((val*mul')+add'\)的形式

\(val*mul*\_mul+add*\_mul+\_add\)

我們發現這樣不需要除法,因此我們選用第二種

其實線段樹標記的下放一般都是這個套路

建議大家做完這道題後再去做一下

這道題

放一下醜陋的程式碼

// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ls k<<1
#define rs k<<1|1
#define int long long 
using namespace std;
const int MAXN=1e6+10;
inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
int N,M,mod;
struct node
{
    int mul,add,sum,l,r,siz;
}T[MAXN];
void update(int k)
{
    T[k].sum=(T[ls].sum%mod+T[rs].sum%mod)%mod;
}
void ps(int x,int f)
{
    T[x].mul=(T[x].mul%mod*T[f].mul%mod)%mod;
    T[x].add=(T[x].add*T[f].mul)%mod;
    T[x].add=(T[x].add+T[f].add)%mod;
    T[x].sum=(T[x].sum%mod*T[f].mul%mod)%mod;
    T[x].sum=(T[x].sum+T[f].add%mod*T[x].siz)%mod;
}
void pushdown(int k)
{
    if(T[k].add==0&&T[k].mul==1) return ;
    ps(ls,k);
    ps(rs,k);
    T[k].add=0;
    T[k].mul=1;
}
void Build(int k,int ll,int rr)
{
    T[k].l=ll;T[k].r=rr;T[k].siz=rr-ll+1;T[k].mul=1;
    if(ll==rr)
    {
        T[k].sum=read()%mod;
        return ;
    }
    int mid=ll+rr>>1;
    Build(ls,ll,mid);
    Build(rs,mid+1,rr);
    update(k);
}
void IntervalMul(int k,int ll,int rr,int val)
{
    if(ll<=T[k].l&&T[k].r<=rr)
    {
        T[k].sum=(T[k].sum*val)%mod;
        T[k].mul=(T[k].mul*val)%mod;
        T[k].add=(T[k].add*val)%mod;
        return ;
    }
    pushdown(k);
    int mid=T[k].l+T[k].r>>1;
    if(ll<=mid) IntervalMul(ls,ll,rr,val);
    if(rr>mid)  IntervalMul(rs,ll,rr,val);
    update(k);
}
void IntervalAdd(int k,int ll,int rr,int val)
{
    if(ll<=T[k].l&&T[k].r<=rr)
    {
        T[k].sum=(T[k].sum+T[k].siz*val)%mod;
        T[k].add=(T[k].add+val)%mod;
        return ;
    }
    pushdown(k);
    int mid=T[k].l+T[k].r>>1;
    if(ll<=mid) IntervalAdd(ls,ll,rr,val);
    if(rr>mid)  IntervalAdd(rs,ll,rr,val);
    update(k);
}
int IntervalSum(int k,int ll,int rr)
{
    int ans=0;
    if(ll<=T[k].l&&T[k].r<=rr)
    {
        ans=(ans+T[k].sum)%mod;
        return ans;
    }
    pushdown(k);
    int mid=T[k].l+T[k].r>>1;
    if(ll<=mid) ans=(ans+IntervalSum(ls,ll,rr))%mod;
    if(rr>mid)  ans=(ans+IntervalSum(rs,ll,rr))%mod;
    return ans%mod;
}
main()
{
    #ifdef WIN32
    freopen("a.in","r",stdin);
    #endif
    N=read();M=read();mod=read();
    Build(1,1,N);
    while(M--)
    {
        int opt=read();
        if(opt==1)
        {
            int l=read(),r=read(),val=read()%mod;
            IntervalMul(1,l,r,val);
        }
        else if(opt==2)
        {
            int l=read(),r=read(),val=read()%mod;
            IntervalAdd(1,l,r,val);
        }
        else if(opt==3)
        {
            int l=read(),r=read();
            printf("%lld\n",IntervalSum(1,l,r)%mod);
        }
    }
    return 0;
}

相關推薦

線段標記下放

感覺題解裡面對加和乘標記下放的順序講的不是很清楚,要麼是直接沒說,要麼是一句話帶過 如果想看1080P高清無碼證明的可以報洛谷冬令營省選班,去看第一天的回放233 假設我們一個節點為\([val,mul,add]\),其中\(val\)代表該節點的權值,\(mul\)為乘法標記,\(add\)為加法標記 那

線段

wid image print d+ 特殊 -c 區間修改 更新 close 數據結構——線段樹 O、引例 A.給出n個數,n<=100,和m個詢問,每次詢問區間[l,r]的和,並輸出。 一種回答:這也太簡單了,O(n)枚舉搜索就行了。

——線段

#include<cstdio> using namespace std; const int maxn = 100005; int n,m,x,y,flag; int l[4*maxn],r[4*maxn];//l[x]:編號為x的單元左端點的數的編號 ,r[x]:編號為x的單元右端點的數

【演算法微解讀】線段

淺談線段樹 (來自TRTTG大佬的供圖) 線段樹個人理解和運用時,認為這個是一個比較實用的優化演算法。 這個東西和區間樹有點相似,是一棵二叉搜尋樹,也就是查詢節點和節點所帶值的一種演算法。 使用線段樹可以快速的查詢某一個節點在若干條線段中出現的次數,時間複雜度為O(logN),這個時間複雜度非常的理想,但是空

hdoj 4578 Transformation 【線段 區間、修改、冪次求和】

Yuanfang is puzzled with the question below:  There are n integers, a1, a2, …, an. The initial values of them are 0. There are four kinds of operations. O

線段(by Shine_hale)

一. 線段樹是什麼? 線段樹,顧名思義,就是將區間變成線段進行處理如圖可以看出,將1-10這個線段不斷拆分,進而得到子節點; 摘自網際網路 二、為什麼要用線段樹 線段樹修改簡單,方便快捷,同時;在查詢上可以使時間複雜度到達O(1),這很厲害了同時不同於RMQ問題,可以線上進行修改,不用花時間進行重構

線段(Segment Tree)

線段樹的定義 百度百科定義如下: 線段樹是一種二叉搜尋樹,與區間樹相似,它將一個區間劃分成一些單元區間,每個單元區間對應線段樹中的一個葉結點。 由定義可知,線段樹實質上是一種二叉搜尋樹,是一棵完全二叉樹,它們的各個節點儲存著一個線段的資訊(這個資訊

線段原理及實現

pri 二叉搜索樹 進行 span 但是 build += std 葉子 大家好,給大家介紹完了樹狀數組(有興趣的讀者可以在我的博客文章中閱讀),現在來給大家介紹另一種數據結構——線段樹。它們結構都有共同點,但是線段樹更為復雜,功能也更為強大,接下來

線段 Segment Tree

   眾所周知,線段樹是algo中很重要的一項!   一.簡介        線段樹是一種二叉搜尋樹,與區間樹相似,它將一個區間劃分成一些單元區間,每個單元區間對應線段樹中的一個葉結點。   使用線段樹可以快速的查詢某一個節點在若干條線段中出現的次數,時間複雜度為O(logN)。而未優化的空

C#語言的各種數據類型,數據類型之間的轉換

優化配置 line com 歸類 浮點 初學者 結構 ali 順序 什麽是數據類型? 數據類型,百度百科是這樣解釋的:數據類型在數據結構中的定義是一個值的集合以及定義在這個值集上的一組操作。這樣的解釋對於一個初學者來說未必太過於深奧。 簡單點說,數據類型就是不同長度的數據的

Luogu 3373 - 【模板】線段 2 - [線段]

query tro 函數 pac upd its c代碼 int typedef 題目鏈接:https://www.luogu.org/problemnew/show/P3373 題目描述 如題,已知一個數列,你需要進行下面三種操作: 1.將某區間每一個數乘上x 2.將某區

線段區間減和區間覆蓋的雙標記問題

oid sca -- clas 覆蓋 ++ get 區間覆蓋 href HDU 5828 吉老師真厲害。 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define lson q <

[模板]線段區間、區間、區間和、區間平方和

1 #include<bits/stdc++.h> 2 #define LL long long 3 #define L(x) x<<1 //左兒子 x*2 4 #define R(x) x<<1|1 //右兒子 x*2+1 5 const

資料結構(B/B+/B-/B*)

一、B樹(二叉搜尋樹) 1、所有非葉子節點至多擁有兩個兒子。 2、所有節點儲存一個關鍵字。 3、左孩子小於父節點,右孩子大於父節點。 二、B-樹(多路搜尋樹)1、定義任意多個非葉子節點最多隻有M個孩子 2、根節點的兒子數【2,M】 3、除根節點之外的非葉子節點的孩子數

C 語言的結構體【struct】聯合體【union】

## C語言中結構 struct 與聯合 union 語法基本一致,如下以 struct 為例 一、struct 的基本用法 struct student {     int num;     char* sex; &nbs

Android開發的MVVM模式及MVP和MVC的區別

三種架構模式的演化: 什麼是MVVM? MVVM是Model-View-ViewModel的簡寫。微軟的WPF帶來了新的技術體驗,如Silverlight、音訊、視訊、3D、動畫……,這導致了軟體UI層更加細節化、可定製化。同時,在技術層面,WPF也帶來

C語言文字檔案二進位制檔案

C語言中,按檔案中的資料組織形式來分,資料檔案可分為ASCII碼檔案(即文字檔案)和二進位制檔案。 文字檔案在磁碟中存放時每個字元對應一個位元組,用於存放對應的ASCII碼。 二進位制檔案把資料按其在記憶體中的儲存形式存放在磁碟上,一個位元組並不一定對應一個字元。 對於A

【遊戲開發】遊戲開發常見的設計原則

依賴關系 unity 說過 srp des log gof https 類繼承   俗話說得好:“設計模式,常讀常新~”。的確,每讀一遍設計模式都會有些新的體會和收獲。馬三不才,才讀了兩遍設計模式(還有一遍是在學校學的),屬於菜鳥級別的。這次準備把閱

trie 及事實上現

空間換時間 字符串 arc com post pre 1.5 dsm back 定義:又稱字典樹,單詞查找樹或者前綴樹,是一種用於高速檢索的多叉樹結構。 如英文字母的字典樹是一個26叉樹,數字的字典樹是一個10叉樹。 核心思想:是空間換時間.利用字符串的公共前綴來

擬物化的巔峰扁平化的崛起

jpg pic blank targe tis 5% size d3d android5 眾所周知,蘋果在iOS7以及OS10.10之後變成了扁平化的設計,或Windows Metro、Android5.0開始,UI的設計風格好像大變了樣,從一個個真實的圖標變成了更加“抽象