洛谷 P3373 線段樹 2

2021-08-17 05:25:32 字數 2793 閱讀 3475

作為一道調了三天的模板題,真的太虐心了對於理解線段樹大有用處。

傳送門如題,已知乙個數列,你需要進行下面三種操作:

1.將某區間每乙個數乘上x

2.將某區間每乙個數加上x

3.求出某區間每乙個數的和

輸入格式:

第一行包含三個整數n、m、p,分別表示該數列數字的個數、操作的總個數和模數。

第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。

接下來m行每行包含3或4個整數,表示乙個操作,具體如下:

操作1: 格式:1 x y k 含義:將區間[x,y]內每個數乘上k

操作2: 格式:2 x y k 含義:將區間[x,y]內每個數加上k

操作3: 格式:3 x y 含義:輸出區間[x,y]內每個數的和對p取模所得的結果

輸出格式:

輸出包含若干行整數,即為所有操作3的結果。

輸入樣例:

5 5 38

1 5 4 2 3

2 1 4 1

3 2 5

1 2 4 2

2 3 5 5

3 1 4

輸出樣例:

172說明

時空限制:1000 ms , 128 m

資料規模:

對於30%的資料:n<=8,m<=10

對於70%的資料:n<=1000,m<=10000

對於100%的資料:n<=100000,m<=100000

樣例說明:

故輸出應為17、2(40 mod 38=2)

題解欲知線段樹是什麼,請看前文 線段樹1

、建樹

同線段樹1:

void bt(int l,int r)

2.區間修改

加法修改同線段樹1:

void add(int now,int l,int r,ll k)

pushdown(now);

int lc=tr[now].lc,rc=tr[now].rc;

int mid=(tr[now].l+tr[now].r)/2;

if(r<=mid) add(lc,l,r,k);

else if(mid+1<=l) add(rc,l,r,k);

else

tr[now].c=(tr[lc].c+tr[rc].c)%p;

}

進行乘法修改時,我們需要把目標區間的 lzm,lza 和目標區間的值都修改。並且每找到一棵子樹就往下推一次 lazy:

void mult(int now,int l,int r,ll k)

pushdown(now);

int lc=tr[now].lc,rc=tr[now].rc;

int mid=(tr[now].l+tr[now].r)/2;

if(r<=mid) mult(lc,l,r,k);

else if(mid+1<=l) mult(rc,l,r,k);

else

tr[now].c=(tr[lc].c+tr[rc].c)%p;

}

3.區間查詢

同線段樹1:

ll findsum(int now,int l,int r)

4.關於取模操作

在每次修改相關的值時(包括 lza , lzm , 與節點本身的值)都對 p 取一次模。

code:

#include#include#define ll long long

struct nodetr[400010];

ll a[100010];

int n,m,len=0;

ll p;

void bt(int l,int r)

else if(l==r) tr[now].c=a[l];

}void pushdown(int now)

void mult(int now,int l,int r,ll k)

pushdown(now);

int lc=tr[now].lc,rc=tr[now].rc;

int mid=(tr[now].l+tr[now].r)/2;

if(r<=mid) mult(lc,l,r,k);

else if(mid+1<=l) mult(rc,l,r,k);

else

tr[now].c=(tr[lc].c+tr[rc].c)%p;

}void add(int now,int l,int r,ll k)

pushdown(now);

int lc=tr[now].lc,rc=tr[now].rc;

int mid=(tr[now].l+tr[now].r)/2;

if(r<=mid) add(lc,l,r,k);

else if(mid+1<=l) add(rc,l,r,k);

else

tr[now].c=(tr[lc].c+tr[rc].c)%p;

}ll findsum(int now,int l,int r)

int main()

if(k==2)

if(k==3) printf("%lld\n",findsum(1,x,y));}}

線段樹2 洛谷p3373 線段樹

題目位址 解釋 多了乙個乘法操作,可以考慮優先順序。每次先算乘法。首先,對於乙個區間 和為s 假設已經按 a 乘b進行了操作。值得到的值為 s a b sb ab 假設先乘得到 sb a 這樣相比,add應該還要再乘上乙個b才對,所以,當更新到乙個區間時,為了進行先乘的操作而不讓結果發生變化,應該將...

洛谷P3373 模板 線段樹2

這題有毒啊,敲了我一晚上加一早上,總算a了。由於有加和乘兩個操作,要用2個lazy陣列。核心難點就是2個lazy陣列會相互影響。因為乘影響加,加不影響乘,所以我們先算乘。include include include include include include include include i...

洛谷 P3373 模板 線段樹 2

如題,已知乙個數列,你需要進行下面三種操作 1.將某區間每乙個數乘上x 2.將某區間每乙個數加上x 3.求出某區間每乙個數的和 第一行包含三個整數n m p,分別表示該數列數字的個數 操作的總個數和模數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來m行每行包含3或4個...