- 直接维护乘积是肯定不可行的, 精度会爆炸, 于是我们来维护对数的和, 最后来计算最高位即可
- 那么转换成区间求和, 区间排序
- 区间排序的方式可以采用线段树维护最大递增块来解决,外层用set来维护线段树的区间, 然后利用线段树的合并分裂性质来操作即可
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<iostream> #include<set> #include<cmath> #define ll long long #define M (1 << 18) #define N 20000010 #define double long double const double eps = 1e-8; using namespace std; int read() { int nm = 0, f = 1; char c = getchar(); for(; !isdigit(c); c = getchar()) if(c == '-') f = -1; for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0'; return nm * f; } double c[M], ver[M]; int num[M], n, m; int lowbit(int x) { return x & -x; } void add(int x, double v) { for(int i = x; i <= n; i += lowbit(i)) c[i] += v; } double query(int x) { double ans = 0; for(int i = x; i; i -= lowbit(i)) ans += c[i]; return ans; } struct Note { int l, r, rt, op; Note(int ln = 0, int rn = 0, int rtn = 0, int opn = 0) { l = ln, r = rn, rt = rtn, op = opn; } bool operator < (const Note &b) const { return this->l < b.l; } }; #define S set<Note>::iterator set<Note> st; int ls[N], rs[N], cnt[N], f; double sum[N]; void pushup(int now) { cnt[now] = cnt[ls[now]] + cnt[rs[now]]; sum[now] = sum[ls[now]] + sum[rs[now]]; } int merge(int x, int y) { if(!x || !y) return x + y; ls[x] = merge(ls[x], ls[y]); rs[x] = merge(rs[x], rs[y]); cnt[x] = cnt[x] + cnt[y]; sum[x] = sum[x] + sum[y]; return x; } S insert(Note x) { add(x.l, sum[x.rt]); return st.insert(x).first; } void Del(S it) { add(it->l, -sum[it->rt]); st.erase(it); } void split(int x, int &rt1, int &rt2, int l, int r, int k) { rt1 = ++f; rt2 = ++f; if(l == r) { cnt[rt1] = k; sum[rt1] = ver[l] * k; cnt[rt2] = cnt[x] - cnt[rt1]; sum[rt2] = sum[x] - sum[rt1]; return; } int mid = (l + r) >> 1; if(cnt[ls[x]] >= k) { rs[rt2] = rs[x]; split(ls[x], ls[rt1], ls[rt2], l, mid, k); } else { ls[rt1] = ls[x]; split(rs[x], rs[rt1], rs[rt2], mid + 1, r, k - cnt[ls[x]]); } pushup(rt1); pushup(rt2); } S split(int x) { if(x > n) return st.end(); S it = st.upper_bound(Note(x, 0, 0, 0)); it--; Note hh = *it; if(hh.l == x) return it; int rt1, rt2; if(!hh.op) split(hh.rt, rt1, rt2, 1, n, x - hh.l); else split(hh.rt, rt2, rt1, 1, n, hh.r - x + 1); Del(it); insert(Note(hh.l, x - 1, rt1, hh.op)); return insert(Note(x, hh.r, rt2, hh.op)); } void build(int &x, int l, int r, int k) { x = ++f; cnt[x]++; sum[x] += ver[k]; if(l == r) return; int mid = (l + r) >> 1; if(k <= mid) build(ls[x], l, mid, k); else build(rs[x], mid + 1, r, k); } int calc(int l, int r) { S L = split(l), R = split(r + 1); R--; double ans = query(R->r) - query(L->l - 1); double out = pow(10, ans - floorl(ans) + eps); return floorl(out); } void updata(int l, int r, int op) { S L = split(l); split(r + 1); int rt = 0; for(S it = L; it != st.end() && (it->l) <= r; Del(it++)) { rt = merge(rt, it->rt); } insert(Note(l, r, rt, op)); } int main() { n = read(), m = read(); for(int i = 1; i <= n; i++) num[i] = read(), ver[i] = log10(i); for(int i = 1; i <= n; i++) { int now; build(now, 1, n, num[i]); insert(Note(i, i, now, 0)); } while(m--) { int op = read(), l = read(), r = read(); if(op == 2) cout << calc(l, r) << "\n"; else { op = read() ^ 1; updata(l, r, op); } } return 0; }
来源:https://www.cnblogs.com/luoyibujue/p/11003496.html