【链接】
http://acm.hdu.edu.cn/showproblem.php?pid=5152
【题意】
给你一个长度为n的序列,有m个操作,3种操作:
1. 给你l,r,输出l-r的和。
2. 修改操作,x,把a[x]->修改为x^a[x]
3. 加操作。l,r,x,l-r区间加x
输出结果对2333333取模。
【思路】
重点在于第二个操作。
A^x = A ^ (x%Phi(C) + Phi(C)) (mod C) (x >= Phi(C))
然后,值得注意是,这道题的Phi(c),是一层套一层的。
最后,题目给出2333333(不是质数),所以Phi(c),最多只有18层。
【代码】
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 100005;
const int MOD = 2333333;
int mo[19] = { 2333333 , 2196720 , 580608 , 165888 , 55296 , 18432 , 6144 , 2048 , 1024 , 512 , 256 , 128 , 64 , 32 , 16 , 8 , 4 , 2 , 1 };
ll sum[maxn << 2];
ll len[maxn << 2];
ll add[maxn << 2];
ll a[maxn];
vector<ll> v[maxn];
int n, m;
int qpow(ll a, ll b, ll mod) {
ll ret = 1;
a %= MOD;
while (b) {
if (b & 1) ret = ret * a % mod;
a = a * a % mod;
b >>= 1;
}
return ret;
}
void pushdown(int n) {
if (add[n]) {
add[n<<1] += add[n];
add[n<<1|1] += add[n];
sum[n<<1] = (sum[n<<1] + add[n] * len[n<<1] % MOD) % MOD;
sum[n<<1|1] = (sum[n<<1|1] + add[n] * len[n<<1|1] % MOD) % MOD;
add[n] = 0;
}
}
void pushup(int n) {
sum[n] = (sum[n<<1] + sum[n<<1|1]) % MOD;
}
void build(int l, int r, int n) {
add[n] = 0;
len[n] = r - l + 1;
if (l == r) {
sum[n] = a[l] % MOD;
return;
}
int mid = (l + r) >> 1;
build(l, mid, n<<1);
build(mid + 1, r, n<<1|1);
pushup(n);
}
void pushupdate(int L, int R, int l, int r, int n, ll v) {
if (L <= l && r <= R) {
add[n] += v;
sum[n] = (sum[n] + len[n] * v) % MOD;
return;
}
pushdown(n);
int mid = (l + r) >> 1;
if (L <= mid) pushupdate(L, R, l, mid, n<<1, v);
if (mid < R) pushupdate(L, R, mid + 1, r, n<<1|1, v);
pushup(n);
}
ll cal(int i, int t) {
if (t == 19) return 0;
ll tmp;
int ch = v[i].size() - 1 - t;
if (t + 1 == v[i].size()) tmp = v[i][ch];
else tmp = qpow(2, cal(i, t + 1), mo[t]) + v[i][ch];
if (tmp >= mo[t]) tmp = tmp % mo[t] + mo[t];
return tmp;
}
void modify(int x, int l, int r, int n) {
if (l == r) {
v[x][v[x].size() - 1] += add[n];
add[n] = 0;
v[x].push_back(0);
sum[n] = cal(x, 0) % MOD;
return;
}
pushdown(n);
int mid = (l + r) >> 1;
if (x <= mid) modify(x, l, mid, n<<1);
else modify(x, mid + 1, r, n<<1|1);
pushup(n);
}
ll query(int L, int R, int l, int r, int n) {
if (L <= l && r <= R) return sum[n];
pushdown(n);
int mid = (l + r) >> 1;
ll ret = 0;
if (L <= mid) ret = (ret + query(L, R, l, mid, n<<1)) % MOD;
if (mid < R) ret = (ret + query(L, R, mid + 1, r, n<<1|1)) % MOD;
return ret;
}
void init() {
for (int i = 0; i <= n; ++i)
v[i].clear();
}
int main() {
while (~scanf("%d%d", &n, &m) ) {
init();
for (int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
v[i].push_back(a[i]);
}
build(1, n, 1);
int op, u, v;
ll w;
for (int i = 0; i<m; ++i) {
scanf("%d", &op);
if (op == 1) {
scanf("%d%d", &u, &v);
printf("%lld\n", query(u, v, 1, n, 1));
}
else if (op == 2) {
scanf("%d", &u);
modify(u, 1, n, 1);
}
else{
scanf("%d%d%lld", &u, &v, &w);
pushupdate(u, v, 1, n, 1, w);
}
}
}
}