[做题记录-数据结构][Ynoi 2013 文化课]
赋值操作可以使得把区间视作多项式实现快速求值。
操作符推平使用区间和以及区间乘积实现快速求值。
剩下的注意计算多项式幂次的时候递推计算减少\(\log\), 剩下的是暴力了。
下面是一份由于没有优化新建空间的过不去代码。
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
class Input {
#define MX 1000000
private :
char buf[MX], *p1 = buf, *p2 = buf;
inline char gc() {
if(p1 == p2) p2 = (p1 = buf) + fread(buf, 1, MX, stdin);
return p1 == p2 ? EOF : *(p1 ++);
}
public :
Input() {
//#define Open_File
#ifdef Open_File
// freopen("a.in", "r", stdin);
// freopen("a.out", "w", stdout);
#endif
}
template <typename T>
inline Input& operator >>(T &x) {
x = 0; int f = 1; char a = gc();
for(; ! isdigit(a); a = gc()) if(a == '-') f = -1;
for(; isdigit(a); a = gc())
x = x * 10 + a - '0';
x *= f;
return *this;
}
inline Input& operator >>(char &ch) {
while(1) {
ch = gc();
if(ch != '\n' && ch != ' ') return *this;
}
}
inline Input& operator >>(char *s) {
int p = 0;
while(1) {
s[p] = gc();
if(s[p] == '\n' || s[p] == ' ' || s[p] == EOF) break;
p ++;
}
s[p] = '\0';
return *this;
}
#undef MX
} Fin;
class Output {
#define MX 1000000
private :
char ouf[MX], *p1 = ouf, *p2 = ouf;
char Of[105], *o1 = Of, *o2 = Of;
void flush() { fwrite(ouf, 1, p2 - p1, stdout); p2 = p1; }
inline void pc(char ch) {
* (p2 ++) = ch;
if(p2 == p1 + MX) flush();
}
public :
template <typename T>
inline Output& operator << (T n) {
if(n < 0) pc('-'), n = -n;
if(n == 0) pc('0');
while(n) *(o1 ++) = (n % 10) ^ 48, n /= 10;
while(o1 != o2) pc(* (--o1));
return *this;
}
inline Output & operator << (char ch) {
pc(ch); return *this;
}
inline Output & operator <<(const char *ch) {
const char *p = ch;
while( *p != '\0' ) pc(* p ++);
return * this;
}
~Output() { flush(); }
#undef MX
} Fout;
#define cin Fin
#define cout Fout
#define endl '\n'
using LL = long long;
inline int log2(unsigned int x);
inline int popcount(unsigned x);
inline int popcount(unsigned long long x);
template<typename T> struct BinaryQueue;
template<typename T>struct BinaryQueue {
__gnu_pbds :: priority_queue<T, less<T>, binary_heap_tag> q;
void push(T x) { q.push(x); }
void pop() { q.pop(); }
} ;
template <int mod>
class Int {
private :
inline int Mod(int x) { return x + ((x >> 31) & mod); }
inline int power(int x, int k) {
int res = 1;
while(k) {
if(k & 1) res = 1LL * x * res % mod;// cerr << k;
x = 1LL * x * x % mod; k >>= 1;
}
return res;
}
public :
int v;
Int(int _v = 0) : v(_v) {}
operator int() { return v; }
inline Int operator =(Int x) { return Int(v = x.v); }
inline Int operator =(int x) { return Int(v = x); }
inline Int operator *(Int x) { return Int(1LL * v * x.v % mod); }
inline Int operator *(int x) { return Int(1LL * v * x % mod); }
inline Int operator +(Int x) { return Int( Mod(v + x.v - mod) ); }
inline Int operator +(int x) { return Int( Mod(v + x - mod) ); }
inline Int operator -(Int x) { return Int( Mod(v - x.v) ); }
inline Int operator -(int x) { return Int( Mod(v - x) ); }
inline Int operator ~() { return Int(power(v, mod - 2)); }
inline Int operator +=(Int x) { return Int(v = Mod(v + x.v - mod)); }
inline Int operator +=(int x) { return Int(v = Mod(v + x - mod)); }
inline Int operator -=(Int x) { return Int(v = Mod(v - x.v)); }
inline Int operator -=(int x) { return Int(v = Mod(v - x)); }
inline Int operator *=(Int x) { return Int(v = 1LL * v * x.v % mod); }
inline Int operator *=(int x) { return Int(v = 1LL * v * x % mod); }
inline Int operator /=(Int x) { return Int(v = v / x.v); }
inline Int operator /=(int x) { return Int(v = v / x); }
inline Int operator ^(int k) { return Int(power(v, k)); }
} ;
using mint = Int<(int) (1e9 + 7)>;
const int N = 1e5 + 5;
struct Poly {
vector<int> pol;
vector<mint> val;
int sz;
Poly(int _sz = 0) {
sz = _sz;
//while(val.size() < sz) val.emplace_back(0);
//while(pol.size() < sz) pol.emplace_back(0);
val.resize(sz); //cerr << sz << endl;
pol.resize(sz);
}
void resize(int _sz) {
//vector<int> x;
//vector<mint> y;
//swap(val, y); swap(pol, x);
//val.clear();
//pol.clear();
sz = _sz;
val.resize(sz); //cerr << sz << endl;
pol.resize(sz);
}
void del(int pos) {
int p = lower_bound(pol.begin(), pol.end(), pos) - pol.begin();
val[p] -= 1;
}
void ins(int pos, int v = 1) {
int l = 0, r = pol.size() - 1, p = r + 1;
while(l <= r) {
int mid = (l + r) >> 1;
if(pol[mid] >= pos) r = mid - 1, p = mid;
else l = mid + 1;
}
//int p = lower_bound(pol.begin(), pol.end(), pos) - pol.begin();
if(p < pol.size() && pol[p] == pos) val[p] += v;
else {
//cerr << pol.size() << ' ';
//int d = pol.size();
pol.insert(pol.begin() + p, pos); //cerr << pos << endl;
val.insert(val.begin() + p, v);
//d -= pol.size();
//assert(d == -1);
//assert(sz + 1 == pol.size());
// cerr << d << endl;
// cerr << (sz + 1) << ' ' << pol.size() << endl;
// sz = pol.size();
sz ++;
//assert(sz == pol.size());
//cerr << sz << ' ' << pol.size() << endl;
//cerr << pol.size() << endl;
}
}
#define mod 1000000007
mint query(mint v) {
mint ans = 0, d = 1;
int lst = 0;
for(int i = 0; i < sz; i ++) {
int k = pol[i] - lst;
mint x = v;
while(k) {
if(k & 1) d *= x;
x *= x; k >>= 1;
}
//d *= v ^ (pol[i] - lst);
ans += d * val[i];
lst = pol[i];
}
return ans;
}
void clear() {
pol.clear(); val.clear();
}
} ;
inline void poly_merge(const Poly &a, const Poly &b, Poly &c) {
static mint val[N];
static int pol[N];
int i = 0, j = 0, k = -1;
while(i < a.sz || j < b.sz) {
//assert(i < a.sz || j < b.sz);
if(i < a.sz && (j >= b.sz || (a.pol[i] <= b.pol[j]))) {
if(k < 0 || pol[k] < a.pol[i]) {
pol[++ k] = a.pol[i];
val[k] = a.val[i];
}
else val[k] += a.val[i];
i ++;
}
else {
if(k < 0 || pol[k] < b.pol[j]) {
pol[++ k] = b.pol[j];
val[k] = b.val[j];
}
else val[k] += b.val[j];
j ++;
}
//cerr <<i;
}
c.resize(k + 1);
for(int i = 0; i <= k; i ++) c.val[i] = val[i], c.pol[i] = pol[i];
//cerr << c.sz << ' ' << c.val.size() << endl;
}
inline Poly operator +(const Poly &a, const Poly &b) {
static mint val[N];
static int pol[N];
int i = 0, j = 0, k = -1;
while(i < a.sz || j < b.sz) {
//assert(i < a.sz || j < b.sz);
if(i < a.sz && (j >= b.sz || (a.pol[i] <= b.pol[j]))) {
if(k < 0 || pol[k] < a.pol[i]) {
pol[++ k] = a.pol[i];
val[k] = a.val[i];
}
else val[k] += a.val[i];
i ++;
}
else {
if(k < 0 || pol[k] < b.pol[j]) {
pol[++ k] = b.pol[j];
val[k] = b.val[j];
}
else val[k] += b.val[j];
j ++;
}
//cerr <<i;
}
Poly c(k + 1);
for(int i = 0; i <= k; i ++) c.val[i] = val[i], c.pol[i] = pol[i];
//cerr << c.sz << ' ' << c.val.size() << endl;
//for(int i = 0; i <= k; i ++) {
// cerr << c.pol[i] << endl;
//}
return c;
}
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
int n, m;
struct Node {
Poly sum_poly; int left_poly, right_poly;
mint cj, sum, left_cj, right_cj, res;
int midopt, left_val, right_val;
int val_tg, opt_tg, len;
} t[N << 2];
int val_seq[N];
int opt_seq[N];
inline Node merge(Node &Left, Node &Right, int midopt) {
Node Merge; //return Merge;
Merge.cj = Left.cj * Right.cj;
Merge.sum = Left.sum + Right.sum;
Merge.left_val = Left.left_val;
Merge.right_val = Right.right_val;
if(midopt == 0) {
poly_merge(Left.sum_poly, Right.sum_poly, Merge.sum_poly);
// Merge.sum_poly = Left.sum_poly + Right.sum_poly;
Merge.left_poly = Left.left_poly;
Merge.right_poly = Right.right_poly;
Merge.left_cj = Left.left_cj;
Merge.right_cj = Right.right_cj;
Merge.res = Left.res + Right.res;
}
else {
poly_merge(Left.sum_poly, Right.sum_poly, Merge.sum_poly);
//Merge.sum_poly = Left.sum_poly + Right.sum_poly;
Merge.sum_poly.del(Left.right_poly);
Merge.sum_poly.del(Right.left_poly);
Merge.sum_poly.ins(Left.right_poly + Right.left_poly, 1);
Merge.left_poly = (Left.left_poly == Left.len ? Left.len + Right.left_poly : Left.left_poly);
Merge.right_poly = (Right.right_poly == Right.len ? Right.len + Left.right_poly : Right.right_poly);
Merge.res = (Left.res - Left.right_cj) + (Right.res - Right.left_cj);
Merge.res += Left.right_cj * Right.left_cj;
Merge.left_cj = (Left.left_poly == Left.len ? Left.cj * Right.left_cj : Left.left_cj);
Merge.right_cj = (Right.right_poly == Right.len ? Right.cj * Left.right_cj : Right.right_cj);
}
return Merge;
}
void update(int x) {
/*
int midopt, left_val, right_val;
int val_tg, opt_tg, len;
*/
int midopt = t[x].midopt;
int val_tg = t[x].val_tg;
int opt_tg = t[x].opt_tg;
int len = t[x].len;
t[x] = merge(t[ls(x)], t[rs(x)], midopt);
t[x].midopt = midopt;
t[x].val_tg = val_tg;
t[x].opt_tg = opt_tg;
t[x].len = len;
//cerr << x << ' ' << t[x].res << endl;
}
void pushdown_val(int x, mint v) {
t[x].val_tg = v;
//cerr << t[x].left_poly << endl;
//cerr << t[x].right_poly << endl;
//cerr << t[x].len << endl;
t[x].left_cj = v ^ t[x].left_poly;
t[x].right_cj = v ^ t[x].right_poly;
t[x].cj = v ^ t[x].len;
t[x].sum = v * t[x].len;
//cerr << t[x].left_poly << endl;
//cerr << t[x].right_poly << endl;
//cerr << v << endl;
t[x].res = t[x].sum_poly.query(v);
//cerr << t[x].res << endl;
t[x].left_val = v;
t[x].right_val = v;
}
void pushdown_opt(int x, int opt) { //cerr << x << endl;
if(t[x].len == 1) return ;
t[x].opt_tg = opt;
t[x].midopt = opt;
if(opt == 0) {
t[x].sum_poly.clear();
t[x].sum_poly.sz = 0;
t[x].sum_poly.ins(1, t[x].len);
t[x].left_poly = t[x].right_poly = 1;
t[x].res = t[x].sum;
t[x].left_cj = t[x].left_val;
t[x].right_cj = t[x].right_val;
}
else {
t[x].sum_poly.clear(); //cerr << t[x].sum_poly.val.size() << endl;
t[x].sum_poly.sz = 0;
t[x].sum_poly.ins(t[x].len, 1);
//cerr << t[x].sum_poly.val.size() << endl;
t[x].left_poly = t[x].right_poly = t[x].len;
t[x].res = t[x].cj;
t[x].left_cj = t[x].cj;
t[x].right_cj = t[x].cj;
}
}
void pushdown(int x) {
if(t[x].opt_tg != -1) {
pushdown_opt(ls(x), t[x].opt_tg);
pushdown_opt(rs(x), t[x].opt_tg);
t[x].opt_tg = -1;
}
if(t[x].val_tg != 0) {
pushdown_val(ls(x), t[x].val_tg);
pushdown_val(rs(x), t[x].val_tg);
t[x].val_tg = 0;
}
}
void build(int x, int l, int r) { //cerr << x << ' ' << l << ' ' << r << endl;
t[x].val_tg = 0;
t[x].opt_tg = -1;
t[x].len = r - l + 1;
// cerr << x << ' ' << l << ' ' << r << endl;
// cerr << x << ' ' << t[x].opt_tg << endl;
if(l == r) {
Poly tmp(1);
tmp.pol[0] = 1;
tmp.val[0] = 1;
t[x].sum_poly = tmp;
t[x].left_poly = t[x].right_poly = 1;
t[x].cj = t[x].sum = t[x].left_cj = t[x].right_cj = t[x].res = val_seq[l];
t[x].left_val = val_seq[l];
t[x].right_val = val_seq[l];
//cerr << x << ' ' << l << ' ' << r << ' ' << t[x].res << endl;
return ;
}
int mid = (l + r) >> 1;
t[x].midopt = opt_seq[mid];
//cerr << mid << endl;
//if(x == 4) cerr << opt_seq[mid] << endl;
build(ls(x), l, mid); build(rs(x), mid + 1, r);
update(x);
// cerr << x << ' ' << l << ' ' << r << ' ' << t[x].res << ' ' << t[x].midopt << endl;
}
void Modify_Val(int x, int l, int r, int L, int R, int val) { //cerr << x << endl;
if(L <= l && r <= R) {
pushdown_val(x, val); return ;
}
//cerr << t[x].opt_tg << endl;
pushdown(x); //cerr << l << ' ' << r << ' ' << L << ' ' << R << endl;
int mid = (l + r) >> 1;
if(L <= mid) Modify_Val(ls(x), l, mid, L, R, val);
if(R > mid) Modify_Val(rs(x), mid + 1, r, L, R, val);
update(x);
}
void Modify_Opt(int x, int l, int r, int L, int R, int opt) {
if(r - l + 1 <= 1) return ;
if(L <= l && r <= R) {
//cerr << x << ' ' << l << ' ' << r << endl;
pushdown_opt(x, opt); return ;
}
pushdown(x);
int mid = (l + r) >> 1;
if(L <= mid && R >= mid) t[x].midopt = opt;
if(L <= mid) Modify_Opt(ls(x), l, mid, L, R, opt);
if(R > mid) Modify_Opt(rs(x), mid + 1, r, L, R, opt);
update(x);
}
Node Query(int x, int l, int r, int L, int R) { //cerr << x << endl;
if(L <= l && r <= R) return t[x];
pushdown(x);
int mid = (l + r) >> 1;
if(L > mid) return Query(rs(x), mid + 1, r, L, R);
if(R <= mid) return Query(ls(x), l, mid, L, R);
Node lps, rps;
lps = Query(ls(x), l, mid, L, R);
rps = Query(rs(x), mid + 1, r, L, R);
// cerr << t[x].midopt << endl;
// cerr << lps.res << ' ' << rps.res << endl;
return merge(lps, rps, t[x].midopt);
}
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i ++) {
unsigned int v;
cin >> v;
v %= (unsigned int) (1e9 + 7);
val_seq[i] = v;
//val_seq[i] %= (int) (1e9 + 7);
}
for(int i = 1; i < n; i ++) cin >> opt_seq[i];
build(1, 1, n); //return 0;
//cout << t[1].res << endl; return 0;
while(m --) {
int op, l, r;
cin >> op >> l >> r; //cerr << op << endl;
if(op == 1) {
unsigned int x; cin >> x; x %= (unsigned int) (1e9 + 7);
Modify_Val(1, 1, n, l, r, x);
}
if(op == 2) {
unsigned int x; cin >> x; x %= (unsigned int) (1e9 + 7);
Modify_Opt(1, 1, n, l, r, x);
}
if(op == 3) {
Node tmp = Query(1, 1, n, l, r);
cout << tmp.res << endl;
}
}
return 0;
}
inline int log2(unsigned int x) { return __builtin_ffs(x); }
inline int popcount(unsigned int x) { return __builtin_popcount(x); }
inline int popcount(unsigned long long x) { return __builtin_popcountl(x); }
// Last Year