「清華集訓2014」玄學-二進位制分組
阿新 • • 發佈:2018-12-14
Description
Solution
考慮對操作二進位制分組。每個塊內維護這個區間的操作把整個序列分成的段數(每一段有兩個值 代表這一段的真實值為 )。
比如相交的兩個操作會形成3段,分別為 ,
由於運算元是 的,所以序列分成的段數也是 的。合併時計算新的段即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long lint;
const int maxn = 600005;
int T, n, mod, q;
int val[maxn], tot, id[maxn], l[maxn * 4], r[maxn * 4];
struct node
{
int p, a, b;
} t[maxn * 30];
int cnt;
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
#define lch (s << 1)
#define rch (s << 1 | 1)
#define mid ((l + r) >> 1)
void build(int s, int l, int r)
{
if (l == r) return id[l] = s, void();
build(lch, l, mid);
build(rch, mid + 1, r);
}
void insert(int L, int R, int a, int b)
{
++tot;
l[id[tot]] = cnt + 1;
if (L > 1) t[++cnt] = (node) {L - 1, 1, 0};
t[++cnt] = (node) {R, a, b};
if (R < n) t[++cnt] = (node) {n, 1, 0};
r[id[tot]] = cnt;
int s = id[tot], i, j, n1, n2;
while ((s & 1) && s > 1) {
s >>= 1;
l[s] = cnt + 1;
i = l[lch]; n1 = r[lch]; j = l[rch]; n2 = r[rch];
while (i <= n1 && j <= n2) {
t[++cnt] = (node) {min(t[i].p, t[j].p), (lint)t[i].a * t[j].a % mod, ((lint)t[j].a * t[i].b + t[j].b) % mod};
if (t[i].p == t[j].p) ++i, ++j;
else if (t[i].p < t[j].p) ++i;
else ++j;
}
r[s] = cnt;
}
}
void calc(int s, int x, int &v)
{
int L = l[s], R = r[s], Mid;
while (L < R) {
Mid = (L + R) >> 1;
if (t[Mid].p >= x) R = Mid;
else L = Mid + 1;
}
v = ((lint)t[L].a * v + t[L].b) % mod;
}
void query(int s, int l, int r, int x, int y, int p, int &v)
{
if (x <= l && r <= y) return calc(s, p, v);
if (x <= mid) query(lch, l, mid, x, y, p, v);
if (y >= mid + 1) query(rch, mid + 1, r, x, y, p, v);
}
int main()
{
T = gi();
n = gi(); mod = gi();
for (int i = 1; i <= n; ++i) val[i] = gi();
q = gi();
build(1, 1, q);
int opt, l, r, a, b, lastans = 0;
for (int i = 1; i <= q; ++i) {
opt = gi();
if (opt == 1) {
l = gi(); r = gi(); a = gi(); b = gi();
if (T & 1) l ^= lastans, r ^= lastans;
insert(l, r, a, b);
} else {
l = gi(); r = gi(); a = gi();
if (T & 1) l ^= lastans, r ^= lastans, a ^= lastans;
b = val[a];
query(1, 1, q, l, r, a, b);
printf("%d\n", lastans = b);
}
}
return 0;
}