#define _CRT_SECURE_NO_WARNINGS #pragma comment(linker, "/STACK:1000000000") #include <algorithm> #include <cstdio> #include <vector> #include <set> using std :: pair; using std :: vector; using std :: set; using std :: make_pair; const int MaxN = 100010; const int MaxQ = 100010; const int MaxS = MaxN + MaxQ; const int K = 100; const int MaxB = MaxS / K + 10; const int MOD = 1000000007; pair < int, int > X[MaxS], Y[MaxS]; int n, q, total; int a[MaxS], ind[MaxS], tmp[MaxS]; set < int > all[MaxS]; struct Node { //Implicit cartesian tree int active, sum, size, index; int y; Node *l, *r; Node(int _index) : index(_index), active(1), sum(1), size(1), y(rand() * RAND_MAX + rand()), l(NULL), r(NULL) { } friend int GetSize(Node *t) { return t != NULL ? t->size : 0; } friend int GetSum(Node *t) { return t != NULL ? t->sum : 0; } friend void Update(Node *t) { if(t != NULL) { t->sum = t->active + GetSum(t->l) + GetSum(t->r); t->size = 1 + GetSize(t->l) + GetSize(t->r); } } friend void Split(Node *t, Node *&l, Node *&r, int key) { if(t == NULL) { l = r = NULL; return; } int my = GetSize(t->l) + 1; if(my <= key) { Split(t->r, t->r, r, key - my); l = t; Update(l); return; } Split(t->l, l, t->l, key); r = t; Update(r); } friend Node *Merge(Node *l, Node *r) { if(!l || !r) { return l ? l : r; } if(l->y < r->y) { l->r = Merge(l->r, r); Update(l); return l; } r->l = Merge(l, r->l); Update(r); return r; } void Debug() { struct Temp { void Print(Node *t) { if(t != NULL) { Print(t->l); printf("%d ", t->index); Print(t->r); } } } y; y.Print(this); printf("\n"); } friend int FindIndex(Node *&root, int x) { //Find x-th 1 in tree Node *now = root; int pos = 0; while(now->l != NULL || now->r != NULL) { int lf = GetSum(now->l); if(x <= lf) { now = now->l; continue; } x -= lf; pos += GetSize(now->l); if(x == now->active) { break; } pos += 1; x -= now->active; now = now->r; } return pos + 1; } friend void SetValue(Node *&root, int Pos, int Val, int Index = -1) { int x = Index == -1 ? FindIndex(root, Pos) : Index; Node *a, *b; Split(root, a, b, x); Split(a, a, root, x - 1); root->active = Val; Update(root); root = Merge(a, Merge(root, b)); } friend void Insert(Node *&root, int Pos, int Index) { if(Pos == 0) { root = Merge(new Node(Index), root); return; } int x = FindIndex(root, Pos); Node *a, *b; Split(root, a, b, x); root = Merge(a, Merge(new Node(Index), b)); } }; //If exists Palindromic Tree, Why not?:) struct DistinctNumbersTree { //But It's just 2D Fenwick Tree int t[MaxB][MaxB], n; vector < int > b; void add(int &a, int b) { if((a += b) >= MOD) { a -= MOD; } } void sub(int &a, int b) { if((a -= b) < 0) { a += MOD; } } void init(int sz, const vector < int > &tmp) { n = sz; b = tmp; for(int i = 0; i <= sz; ++i) { for(int j = 0; j <= sz; ++j) { t[i][j] = 0; } } } void upd2(int x, int y, int val) { for(int i = x; i <= n; i |= i + 1) { for(int j = y; j <= n; j |= j + 1) { add(t[i][j], val); } } } void upd(int x, int y, int val) { if(val < 0) { val = MOD - b[-val - 1]; } else { val = b[val - 1]; } upd2(x / K, y / K, val); } int sum(int x, int y) { int ret = 0; for(int i = x; i >= 0; i &= i + 1, --i) { for(int j = y; j >= 0; j &= j + 1, --j) { add(ret, t[i][j]); } } return ret; } int query(int p, int q) { int ret = 0; if(q - p <= 4 * K) { // if length of [p..q] small, naive: for(int i = p; i <= q; ++i) { int bal = (X[i].first >= p && X[i].first <= q) - (X[i].second >= p && X[i].second <= q); if(bal != 0) add(ret, b[a[i] - 1]); } return ret; } //Split interval [p..q] into three intervals [p..(ceil(p/K)*K-1)], [ceil(L/K)*K..floor(R/K)*K-1], [floor(R/K)*K..q] //For first and third I used next fact - in each row and each column not more than two non-zero values(we can maintain these values) //For second interval I used two dimensional Fenwick tree int L = (p + K - 1) / K, R = q / K; add(ret, sum(R - 1, R - 1)); sub(ret, sum(R - 1, L - 1)); sub(ret, sum(L - 1, R - 1)); add(ret, sum(L - 1, L - 1)); L *= K; R *= K; for(int i = p; i < L; ++i) { int dx = (X[i].first >= p && X[i].first <= q) - (X[i].second >= p && X[i].second <= q); int dy = -(Y[i].first >= L && Y[i].first < R) + (Y[i].second >= L && Y[i].second < R); if(dx != 0) add(ret, b[a[i] - 1]); if(dy != 0) sub(ret, b[a[i] - 1]); } for(int i = R; i <= q; ++i) { int dx = (X[i].first >= p && X[i].first <= q) - (X[i].second >= p && X[i].second <= q); int dy = -(Y[i].first >= L && Y[i].first < R) + (Y[i].second >= L && Y[i].second < R); if(dx != 0) add(ret, b[a[i] - 1]); if(dy != 0) sub(ret, b[a[i] - 1]); } return ret; } } pow0, pow1, pow2, pow3; struct Query { int c, l, r; } Q[MaxQ]; void Read() { scanf("%d%d", &n, &q); for(int i = 1; i <= n; ++i) { scanf("%d", &a[i]); } for(int i = 1; i <= q; ++i) { scanf("%d%d", &Q[i].c, &Q[i].l); if(Q[i].c != 3) { scanf("%d", &Q[i].r); } } } void Move(Node *root, int tmp) { if(root != NULL) { Move(root->l, tmp); Move(root->r, tmp); root->active = (root->index <= tmp); Update(root); } } void Order(Node *root, int &ptr) { if(root != NULL) { Order(root->l, ptr); ind[root->index] = ++ptr; Order(root->r, ptr); } } void GetIndexes() { Node *root = NULL; for(int i = 1; i <= n; ++i) { Insert(root, i - 1, ++total); } for(int i = 1; i <= q; ++i) { if(Q[i].c == 3) { SetValue(root, Q[i].l, 0); } else if(Q[i].c == 4) { Insert(root, Q[i].l, ++total); //Add new item in Carteian tree } } Move(root, n); int now = 0; Order(root, now); for(int i = 1, temp = n; i <= q; ++i) { int fl = (Q[i].c != 4 ? FindIndex(root, Q[i].l) : ind[++temp]); int fr = (Q[i].c % 4 == 1 ? FindIndex(root, Q[i].r) : -1); if(Q[i].c == 3) { SetValue(root, fl, 0, fl); } else if(Q[i].c == 4) { SetValue(root, fl, 1, fl); } Q[i].l = fl; if(fr != -1) { Q[i].r = fr; } } } void upd(int x, int y, int val) { pow0.upd(x, y, val); pow1.upd(x, y, val); pow2.upd(x, y, val); pow3.upd(x, y, val); } void erase(int pos) { int old = a[pos]; set < int > :: iterator it, pre, nxt; set < int > &s = all[old]; nxt = it = s.lower_bound(pos); ++nxt; if(it != s.begin()) { pre = it; --pre; } else { pre = s.end(); } X[*it] = Y[*it] = make_pair(-1, -1); upd(*it, *it, -old); if(pre != s.end()) { upd(*pre, *it, old); X[*pre].second = -1; } if(nxt != s.end()) { upd(*it, *nxt, old); Y[*nxt].first = -1; } if(pre != s.end() && nxt != s.end()) { upd(*pre, *nxt, -old); X[*pre].second = *nxt; Y[*nxt].first = *pre; } s.erase(pos); a[pos] = 0; } void insert(int pos, int val) { all[val].insert(pos); set < int > :: iterator it, pre, nxt; set < int > &t = all[val]; nxt = it = t.lower_bound(pos); ++nxt; if(it != t.begin()) { pre = it; --pre; } else { pre = t.end(); } upd(*it, *it, val); X[pos].first = Y[pos].second = pos; if(nxt != t.end()) { upd(*it, *nxt, -val); X[pos].second = *nxt; Y[*nxt].first = pos; } if(pre != t.end()) { upd(*pre, *it, -val); X[*pre].second = *it; Y[*it].first = *pre; } if(pre != t.end() && nxt != t.end()) { upd(*pre, *nxt, val); } a[pos] = val; } void BuildTree() { int size = total / K + 1; vector < int > p0, p1, p2, p3, b; for(int i = 1; i <= n; ++i) { b.push_back(a[i]); } for(int i = 1; i <= q; ++i) { if(Q[i].c % 2 == 0) { b.push_back(Q[i].r); } } sort(b.begin(), b.end()); b.erase(unique(b.begin(), b.end()), b.end()); // Compress all values for(int i = 1; i <= n; ++i) { a[i] = lower_bound(b.begin(), b.end(), a[i]) - b.begin() + 1; tmp[ind[i]] = a[i]; } // Build four DistinctNumbersTree(for sum of 3rd, 2nd, 1st and 0th powers of distinct numbers) p0.resize(b.size()); p1.resize(b.size()); p2.resize(b.size()); p3.resize(b.size()); for(int i = 0; i < b.size(); ++i) { p0[i] = 1; p1[i] = 1LL * p0[i] * b[i] % MOD; p2[i] = 1LL * p1[i] * b[i] % MOD; p3[i] = 1LL * p2[i] * b[i] % MOD; } pow0.init(size, p0); pow1.init(size, p1); pow2.init(size, p2); pow3.init(size, p3); for(int i = 1; i <= q; ++i) { if(Q[i].c % 2 == 0) { Q[i].r = lower_bound(b.begin(), b.end(), Q[i].r) - b.begin() + 1; } } for(int i = 1; i <= total; ++i) { a[i] = tmp[i]; X[i] = Y[i] = make_pair(-1, -1); } for(int i = 1; i <= total; ++i) { //Build 2D-table if(a[i] == 0) { continue; } upd(i, i, a[i]); X[i] = make_pair(i, -1); Y[i] = make_pair(i, -1); if(!all[a[i]].empty()) { int last = *--all[a[i]].end(); upd(last, i, -a[i]); X[last].second = i; Y[i].first = last; Y[i].second = i; } all[a[i]].insert(all[a[i]].end(), i); } } int Inv(int n) { // Inverse element return n == 1 ? n : 1LL * (MOD - MOD / n) * Inv(MOD % n) % MOD; } int calc(int s1, int s2, int s3) { int a1 = s1; int a2 = (1LL * s1 * s1 - s2 + MOD) % MOD * Inv(2) % MOD; return (1LL * a2 * s1 - 1LL * a1 * s2 + s3 + 1LL * MOD * MOD) % MOD * Inv(3) % MOD; } void Solve() { for(int i = 1; i <= q; ++i) { if(Q[i].c == 1) { printf("%d\n", calc(pow1.query(Q[i].l, Q[i].r), pow2.query(Q[i].l, Q[i].r), pow3.query(Q[i].l, Q[i].r))); } else if(Q[i].c == 2) { if(a[Q[i].l] != Q[i].r) { erase(Q[i].l); insert(Q[i].l, Q[i].r); } } else if(Q[i].c == 3) { erase(Q[i].l); } else if(Q[i].c == 4) { insert(Q[i].l, Q[i].r); } else { printf("%d\n", pow0.query(Q[i].l, Q[i].r)); } } } void Stupid() { for(int i = 1; i <= q; ++i) { if(Q[i].c == 1) { vector < int > b; for(int j = Q[i].l; j <= Q[i].r; ++j) { b.push_back(a[j]); } sort(b.begin(), b.end()); b.resize(unique(b.begin(), b.end()) - b.begin()); int s1 = 0, s2 = 0, s3 = 0; for(int x = 0; x < b.size(); ++x) { s1 = (s1 + b[x]) % MOD; s2 = (s2 + 1LL * b[x] * b[x]) % MOD; s3 = (s3 + 1LL * b[x] * b[x] % MOD * b[x]) % MOD; } printf("%d\n", calc(s1, s2, s3)); } else if(Q[i].c == 2) { a[Q[i].l] = Q[i].r; } else if(Q[i].c == 3) { for(int j = Q[i].l; j < n; ++j) { a[j] = a[j + 1]; } n -= 1; } else if(Q[i].c == 4) { for(int j = n + 1; j - 1 > Q[i].l; --j) { a[j] = a[j - 1]; } a[Q[i].l + 1] = Q[i].r; n += 1; } else { vector < int > b; for(int j = Q[i].l; j <= Q[i].r; ++j) { b.push_back(a[j]); } sort(b.begin(), b.end()); b.resize(unique(b.begin(), b.end()) - b.begin()); printf("%d\n", (int)b.size()); } } } int main() { Read(); GetIndexes(); BuildTree(); Solve(); // Stupid(); return 0; }