P3373
AC代码:
这里的延迟标记要开两个,分别记录加法的值和乘法的值,但是乘法和加法的优先级不一样,不规定他们的顺序的话会有错误,所以可以规定乘法优先,即规定好该结点的值等于该节点的值*父节点的乘法延迟标记的值+父节点加法延迟标记的值*区间长度,即,sum[num * 2] = (sum[num * 2] * Add[num].wc + ln * Add[num].wj) % mod;这样的话假如改变wj的数值就只改变wj,改变wc的时候把wc也对应的乘一下就可以了。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 100100;
ll n, m, mod;
ll a[maxn];
ll sum[maxn * 4];
struct A
{
ll flag;
ll wc, wj;
} Add[maxn * 4];
void PushUp(ll n)
{
sum[n] = (sum[n * 2] + sum[n * 2 + 1]) % mod;
return;
}
//建树
void Build(ll l, ll r, ll num)
{
if (l == r)
{
sum[num] = a[l];
return;
}
ll m = (l + r) / 2;
Build(l, m, num * 2);
Build(m + 1, r, num * 2 + 1);
PushUp(num);
return;
}
void PushDown(ll num, ll ln, ll rn)
{
if (Add[num].flag)
{
sum[num * 2] = (sum[num * 2] * Add[num].wc + ln * Add[num].wj) % mod;
sum[num * 2 + 1] = (sum[num * 2 + 1] * Add[num].wc + Add[num].wj * rn) % mod;
Add[num * 2].wj = (Add[num * 2].wj * Add[num].wc + Add[num].wj) % mod;
Add[num * 2 + 1].wj = (Add[num * 2 + 1].wj * Add[num].wc + Add[num].wj) % mod;
Add[num * 2].wc = (Add[num * 2].wc * Add[num].wc) % mod;
Add[num * 2 + 1].wc = (Add[num * 2 + 1].wc * Add[num].wc) % mod;
Add[num].flag = 0;
Add[num].wj = 0;
Add[num].wc = 1;
Add[num * 2].flag = 1;
Add[num * 2 + 1].flag = 1;
}
return;
}
void Update(ll op, ll L, ll R, ll C, ll l, ll r, ll num)
{
if (R < l || L > r)
return ;
if (l >= L && R >= r)
{
if(op==1)
{
sum[num] = (sum[num] + C * (r - l + 1)) % mod;
Add[num].wj = ( Add[num].wj + C ) % mod;
Add[num].flag = 1;
return;
}
if(op==-1)
{
sum[num] = (sum[num] * C) % mod;
Add[num].wc = (Add[num].wc * C) % mod;
Add[num].wj = (Add[num].wj * C) % mod;
Add[num].flag = 1;
return;
}
return;
}
ll m = (l + r) / 2;
PushDown(num, m - l + 1, r - m); //下推标记
if (L <= m)
Update(op, L, R, C, l, m, num * 2);
if (R >= m + 1)
Update(op, L, R, C, m + 1, r, num * 2 + 1);
PushUp(num);
return;
}
//区间查询 查询区间 L-R
ll Query(ll L, ll R, ll l, ll r, ll num)
{
if (R < l || L > r)
return 0;
if (L <= l && R >= r)
{
return sum[num]%mod;
}
ll m = (l + r) / 2;
PushDown(num, m - l + 1, r - m);
ll ans = 0;
if (L <= m)
ans += Query(L, R, l, m, num * 2);
if (R >= m + 1)
ans += Query(L, R, m + 1, r, num * 2 + 1);
return ans%mod;
}
int main()
{
for (int i = 0; i < maxn * 4;i++)
{
Add[i].flag = 0;
Add[i].wc = 1;
Add[i].wj = 0;
}
ll x, y, k, z;
scanf("%lld %lld %lld", &n, &m, &mod);
for (int i = 1; i <= n;i++)
scanf("%lld", &a[i]);
Build(1, n, 1);
while (m--)
{
scanf("%lld", &z);
if(z==1)
{
scanf("%lld %lld %lld", &x, &y, &k);
Update(-1, x, y, k%mod, 1, n, 1);
}
else if(z==2)
{
scanf("%lld %lld %lld", &x, &y, &k);
Update(1, x, y, k%mod, 1, n, 1);
}
else if(z==3)
{
scanf("%lld %lld", &x, &y);
printf("%lld\n", Query(x, y, 1, n, 1));
}
}
return 0;
}
刚开始的思路也是开两个延迟标记分别记录,然后因为没想到怎么处理乘法和加法的优先级问题,所以干脆直接推下去算了(如果给该节点标记乘法延迟标记的时候发现该结点已经存在加法的延迟标记,就把加法的延迟标记推下去(这里是一个递归的过程),再标记乘法的延迟标记),这样就保证了一个节点只会存在一种延迟标记,但是他T了。。
T的代码:
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <cstdio>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 100100;
ll n, m, mod;
ll a[maxn];
ll sum[maxn * 4];
struct A
{
ll flag;
ll wc,wj;
} Add[maxn * 4];
void PushUp(ll n)
{
sum[n] = (sum[n * 2] + sum[n * 2 + 1]) % mod;
return;
}
//建树
void Build(ll l, ll r, ll num)
{
if (l == r)
{
sum[num] = a[l];
return;
}
ll m = (l + r) / 2;
Build(l, m, num * 2);
Build(m + 1, r, num * 2 + 1);
PushUp(num);
return;
}
void PushDown(ll num, ll ln, ll rn, ll l, ll r)
{
if (ln < 0 || rn < 0)
return;
if (l >= r)
return;
if (num >= maxn)
return;
if (Add[num].flag == 1)
{
if (Add[num * 2].flag != 0)
{
ll lll = l;
ll rrr = (l + r) / 2;
ll mid = (lll + rrr) / 2;
PushDown(num * 2, mid - lll + 1, rrr - mid, lll, rrr);
}
if (Add[num * 2 + 1].flag != 0)
{
ll lll = (l + r) / 2 + 1;
ll rrr = r;
ll mid = (lll + rrr) / 2;
PushDown(num * 2 + 1, mid - lll + 1, rrr - mid, lll, rrr);
}
Add[num * 2].wj = Add[num * 2].wj % mod + Add[num].wj % mod;
Add[num * 2 + 1].wj = Add[num * 2 + 1].wj % mod + Add[num].wj % mod;
Add[num * 2].flag = 1;
Add[num * 2 + 1].flag = 1;
sum[num * 2] = sum[num * 2] % mod + ((Add[num].wj % mod) * (ln % mod)) % mod;
sum[num * 2 + 1] = sum[num * 2 + 1] % mod + ((Add[num].wj % mod) * (rn % mod)) % mod;
Add[num].flag = 0;
Add[num].wj = 0;
}
if (Add[num].flag==-1)
{
if (Add[num * 2].flag != 0)
{
ll lll = l;
ll rrr = (l + r) / 2;
ll mid = (lll + rrr) / 2;
PushDown(num * 2, mid - lll + 1, rrr - mid, lll, rrr);
}
if (Add[num * 2 + 1].flag != 0)
{
ll lll = (l + r) / 2 + 1;
ll rrr = r;
ll mid = (lll + rrr) / 2;
PushDown(num * 2 + 1, mid - lll + 1, rrr - mid, lll, rrr);
}
Add[num * 2].wc = ((Add[num * 2].wc % mod) * (Add[num].wc % mod)) % mod;
Add[num * 2 + 1].wc = ((Add[num * 2 + 1].wc % mod) * (Add[num].wc % mod)) % mod;
Add[num * 2].flag = -1;
Add[num * 2 + 1].flag = -1;
sum[num * 2] = ((sum[num * 2] % mod) * (Add[num].wc % mod)) % mod;
sum[num * 2 + 1] = ((sum[num * 2 + 1] % mod) * (Add[num].wc % mod)) % mod;
Add[num].flag = 0;
Add[num].wc = 1;
}
return;
}
void Update(ll op, ll L, ll R, ll C, ll l, ll r, ll num)
{
if (R < l || L > r)
return ;
if (l >= L && R >= r)
{
if(op==1)
{
if(Add[num].flag==-1)
{
ll m = (l + r) / 2;
PushDown(num, m - l + 1, r - m, l, r);
}
sum[num] =((sum[num]%mod) + ( C * (r - l + 1) )%mod)%mod;
Add[num].wj = ((Add[num].wj % mod) + (C % mod)) % mod;
Add[num].flag = op;
return;
}
if(op==-1)
{
if(Add[num].flag==1)
{
ll m = (l + r) / 2;
PushDown(num, m - l + 1, r - m, l, r);
}
sum[num] = ((sum[num] % mod) * (C % mod)) % mod;
Add[num].wc = ((Add[num].wc % mod) * (C % mod)) % mod;
Add[num].flag = op;
return;
}
return;
}
ll m = (l + r) / 2;
PushDown(num, m - l + 1, r - m, l, r); //下推标记
if (L <= m)
Update(op, L, R, C, l, m, num * 2);
if (R >= m + 1)
Update(op, L, R, C, m + 1, r, num * 2 + 1);
PushUp(num);
return;
}
//区间查询 查询区间 L-R
ll Query(ll L, ll R, ll l, ll r, ll num)
{
if (R < l || L > r)
return 0;
if (L <= l && R >= r)
{
return sum[num]%mod;
}
ll m = (l + r) / 2;
PushDown(num, m - l + 1, r - m, l, r);
ll ans = 0;
if (L <= m)
ans += Query(L, R, l, m, num * 2);
if (R >= m + 1)
ans += Query(L, R, m + 1, r, num * 2 + 1);
return ans%mod;
}
int main()
{
for (int i = 0; i < maxn * 4;i++)
{
Add[i].flag = 0;
Add[i].wc = 1;
Add[i].wj = 0;
}
ll x, y, k, z;
scanf("%lld %lld %lld", &n, &m, &mod);
for (int i = 1; i <= n;i++)
scanf("%lld", &a[i]);
Build(1, n, 1);
while (m--)
{
scanf("%lld", &z);
if(z==1)
{
scanf("%lld %lld %lld", &x, &y, &k);
Update(-1, x, y, k%mod, 1, n, 1);
}
else if(z==2)
{
scanf("%lld %lld %lld", &x, &y, &k);
Update(1, x, y, k%mod, 1, n, 1);
}
else if(z==3)
{
scanf("%lld %lld", &x, &y);
printf("%lld\n", Query(x, y, 1, n, 1));
}
}
return 0;
}