线段树
注:本线段树使用链表形式(指针),每个结点都是左闭右闭区间。
操作为加或乘,最后答案模 (mod)。
打两个标记,分别为 add
和 mul
。
ll n, m, mod;
struct node{
ll L, R, add, mul, sum;
node *lc, *rc;
void makeadd(ll k)
{
sum = (sum + k * (R - L + 1)) % mod;
add = (add + k) % mod;
}
void makemul(ll k)
{
sum = (sum * k) % mod;
mul = (mul * k) % mod;
add = (add * k) % mod;
}
void pushup()
{
sum = (lc->sum + rc->sum) % mod;
}
void pushdown()
{
if(mul != 1)
{
lc->makemul(mul);
rc->makemul(mul);
mul = 1;
}
if(add)
{
lc->makeadd(add);
rc->makeadd(add);
add = 0;
}
}
};
const ll N = 1e5 + 4;
ll a[N];
void Build(node *now, ll l, ll r)
{
now->L = l;
now->R = r;
now->add = 0;
now->mul = 1;
now->sum = 0;
if(l < r)
{
ll mid = (l + r) >> 1;
now->lc = new node;
now->rc = new node;
Build(now->lc, l, mid);
Build(now->rc, mid + 1, r);
now->pushup();
}
else
{
now->sum = a[l];
now->lc = now->rc = NULL;
}
}
ll check(node *now, ll l, ll r)
{
if(l <= now->L and now->R <= r)
return now->sum % mod;
now->pushdown();
ll mid = (now->L + now->R) >> 1;
ll ans = 0;
if(l <= mid)
ans = (ans + check(now->lc, l, r)) % mod;
if(mid < r)
ans = (ans + check(now->rc, l , r)) % mod;
return ans % mod;
}
void add(node *now, ll l, ll r, ll k)
{
if(l <= now->L and now->R <= r)
now->makeadd(k);
else
{
now->pushdown();
ll mid = (now->L + now->R) >> 1;
if(l <= mid)
add(now->lc, l, r, k);
if(mid < r)
add(now->rc, l, r, k);
now->pushup();
}
}
void mul(node *now, ll l, ll r, ll k)
{
if(l <= now->L and now->R <= r)
now->makemul(k);
else
{
now->pushdown();
ll mid = (now->L + now->R) >> 1;
if(l <= mid)
mul(now->lc, l, r, k);
if(mid < r)
mul(now->rc, l, r, k);
now->pushup();
}
}
int main()
{
n = read(), m = read(), mod = read();
for(int i = 1; i <= n; ++i)
a[i] = read();
node *root;
root = new node;
Build(root, 1, n);
for(int i = 1; i <= m; ++i)
{
ll opt = read(), l = read(), r = read(), k;
if(opt == 1)
{
k = read();
mul(root, l, r, k);
}
if(opt == 2)
{
k = read();
add(root, l ,r, k);
}
if(opt == 3)
{
printf("%lld
", check(root, l, r) % mod);
}
}
return 0;
}