作為一道調了三天的模板題,真的太虐心了對於理解線段樹大有用處。
傳送門如題,已知乙個數列,你需要進行下面三種操作:
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個...