線段樹 區間乘法加法混合
線段樹 區間乘法加法混合
本題AC程式碼:
#include<iostream>
#include<cstdio>
#include<string>
#include<algorithm>
using namespace std;
#define ll long long
#define N 500005
ll s[N];
ll P;
struct tree
{
ll l,r,len;
ll v,color,color1;
}tre[N];
void build_tree(ll a,ll l,ll r)
{
tre[a].color=0;tre[a].color1=1;
tre[a].l=l;tre[a].r=r;tre[a].len=r-l+1;
if(tre[a].l==tre[a].r){tre[a].v=s[l]%P;return ;}
ll mid=(tre[a].l+tre[a].r)/2;
build_tree(2*a,l,mid);
build_tree(2*a+1,mid+1,r);
tre[a].v=(tre[2*a].v+tre[2*a+1].v)%P;
}
void pushdown(ll a)
{
if(tre[a].color==0&&tre[a].color1==1)return ;
tre[2*a].v=tre[2*a].v*tre[a].color1%P;
tre[2*a+1].v=tre[2*a+1].v*tre[a].color1%P;
tre[2*a].v=(tre[2*a].v+tre[a].color*tre[2*a].len)%P;
tre[2*a+1].v=(tre[2*a+1].v+tre[a].color*tre[2*a+1].len)%P;
tre[2*a].color1=(tre[a].color1*tre[2*a].color1)%P;
tre[2*a+1].color1=(tre[a].color1*tre[2*a+1].color1)%P;
tre[2*a].color=(tre[2*a].color*tre[a].color1+tre[a].color)%P;
tre[2*a+1].color=(tre[2*a+1].color*tre[a].color1+tre[a].color)%P;
tre[a].color1=1;tre[a].color=0;
}
void add_tree(ll a,ll l,ll r,ll k)
{
if(tre[a].l>=l&&tre[a].r<=r)
{
tre[a].v=(tre[a].v+tre[a].len*k)%P;
tre[a].color=(tre[a].color+k)%P;
return;
}
ll mid=(tre[a].l+tre[a].r)/2;pushdown(a);
if(l<=mid)add_tree(2*a,l,r,k);
if(r>mid)add_tree(2*a+1,l,r,k);
tre[a].v=(tre[2*a].v+tre[2*a+1].v)%P;
//cout<<tre[1].v<<' '<<tre[2].v<<' '<<tre[3].v<<' '<<tre[4].v<<' '<<tre[5].v<<' '<<tre[6].v<<' '<<tre[7].v<<' '<<tre[8].v<<' '<<tre[9].v<<endl;
}
void mul_tree(ll a,ll l, ll r,ll k)
{
if(tre[a].l>=l&&tre[a].r<=r)
{
tre[a].v=((tre[a].v%P)*(k%P))%P;
tre[a].color1=tre[a].color1*k%P;
tre[a].color=tre[a].color*k%P;
return ;
}
ll mid=(tre[a].l+tre[a].r)/2;pushdown(a);
if(l<=mid)mul_tree(2*a,l,r,k);
if(r>mid)mul_tree(2*a+1,l,r,k);
tre[a].v=(tre[2*a].v+tre[2*a+1].v)%P;
}
ll find_tree(ll a,ll l,ll r)
{
if(tre[a].l>=l&&tre[a].r<=r)return tre[a].v%P;
ll mid=(tre[a].l+tre[a].r)/2;pushdown(a);
ll ans=0;
if(l<=mid)ans=(ans%P+find_tree(2*a,l,r)%P)%P;
if(r>mid)ans=(ans%P+find_tree(2*a+1,l,r)%P)%P;
return ans%P;
}
int main()
{
ll n,m;
cin>>n>>m>>P;
for(int i=1;i<=n;i++)cin>>s[i];
build_tree(1,1,n);
ll op,ans,kase,k;
while(m--)
{
cin>>op;
if(op==2)
{
cin>>ans>>kase>>k;
add_tree(1,ans,kase,k);
}
if(op==1)
{
cin>>ans>>kase>>k;
mul_tree(1,ans,kase,k);
}
if(op==3)
{
cin>>ans>>kase;
cout<<find_tree(1,ans,kase)%P<<endl;
}
}
return 0;
}
此題和之前的線段樹 區間加法相似,主要的區別和難點在於怎麼處理加法和乘法的混合標記轉移。
比如說 陣列 :1 2 3 4 5
如果在區間2 到 4 上加 2
陣列就變成:1 2+2 3+2 4+2 5
如果在區間2 到 5 上乘2
陣列就變成:1 2X2+2X2 3X2+2X2 4X2+2X2 5X2
細心的盆友可能發現了:
當經歷了乘法運算後,原有的加法也要乘相應的數沒這樣才能保證精度一致。
相關文章
- 線段樹(3)——區間操作疊加
- HDU 2795 Billboard(線段樹 區間最大)
- 芻議線段樹 2 (區間修改,區間查詢)
- 線段樹維護區間等差數列
- Codeforces Round #675 (Div. 2) 1442 F - Boring Queries 可持久化線段樹維護 區間乘法持久化
- POJ 3468 【區間修改+區間查詢 樹狀陣列 | 線段樹 | 分塊】陣列
- HDU 3397 Sequence operation(線段樹區間染色加區間合併)
- 區間k小值(可持久化線段樹)持久化
- HDU 1754 I Hate It (線段樹 區間最值)
- POJ 3468 A Simple Problem with Integers (線段樹 區間共加)
- HDU1698 Just a Hook【線段樹基礎:區間修改+區間查詢】Hook
- 大數加法乘法
- HDU 4027 Can you answer these queries? (線段樹 區間開方)
- 區間演算法題用線段樹可以秒解?演算法
- POJ 2528 Mayor's posters (線段樹 區間更新+離散化)
- 橢圓曲線加密中的加法乘法淺析加密
- 【知識點】淺入線段樹與區間最值問題
- 【Leetcode每日一題】327. 區間和的個數(線段樹/樹狀陣列)LeetCode每日一題陣列
- 線段樹
- 線~段~樹
- HDU1754 I Hate It 【線段樹基礎:點修改+區間查詢】
- 線段樹(1)建樹、單點修改、單點查詢、區間查詢和例題
- 一些線段樹典(求求了區域賽遇到線段樹不要被卡了)
- 01 線段樹
- 線段樹--RMQMQ
- 【模版】線段樹
- 線段樹模板
- 線段樹 hate it
- P8868 [NOIP2022] 比賽(線段樹維護區間歷史和)
- 線段樹維護單調棧——區間查詢版本 & 維護遞減序列
- 洛谷P1712 [NOI2016]區間 尺取法+線段樹+離散化
- HDU1166 敵兵佈陣【線段樹基礎:點修改+區間查詢】
- 加法、乘法、除法:綜合謎題(1)
- 加法、乘法、除法:綜合謎題(2)
- ut.cpp 最大線段並減線段交 [線段樹]
- 李超線段樹
- 線段樹進階
- 權值線段樹