CF1599E Two Arrays

发布时间 2023-09-20 11:37:24作者: Ender_32k

Dq17 y。

考虑斐波那契通项公式,分别维护区间 \(\left(\frac{1+\sqrt 5}{2}\right)^{a_{1,i}+a_{2,i}}\)\(\left(\frac{1-\sqrt 5}{2}\right)^{a_{1,i}+a_{2,i}}\) 的和。显然可以扩域,定义一个 \(n=a+\sqrt 5b\) 的结构体即可。然后快速求斐波那契数列某项就可以直接快速幂了。

然后就是线段树心跳板子。很难写,不想写。

然而有个看起来复杂度很假的做法。

考虑简化 segment tree beats,直接维护区间 \(\max\),区间 \(\min\)。考虑区间对 \(c\)\(\max\) 操作,若区间 \(\min\ge c\),则修改对区间没有影响,可以直接 return 掉;否则递归下去,但是要等到找到连续段才进行修改。区间取 \(\min\) 同理。而对于区间加,直接维护加法标记即可。

显然区间加法、区间查询的复杂度是正确的,考虑区间取 \(\min\) 或者 \(\max\)

\(B\) 为序列总连续段数,假设这次修改影响了 \(c\) 个连续段,那么 \(B'\gets B'-c+k\)\(k\) 为新增的连续段数。并且这次修改的复杂度应该是 \(O(c\log n)\) 的(可以认为是修改是把区间要被修改的连续段,每段分成 \(\log n\) 个线段树区间)。

问题是 \(k\) 可能很大,感性理解一下,发现 \(k\) 其实就是区间中没有被影响到的连续段数 \(+1\)。所以 \(\sum c\) 不一定与 \(n\) 同阶。

这东西是可以且很容易被卡满的(比如这样),所以我们就成功证明出这个做法的复杂度,其实就是是假的。

但是直接过了,还怪好写的嘞。所以正确做法以后再补吧。

// Problem: Two Arrays
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1599E
// Memory Limit: 250 MB
// Time Limit: 5000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define int long long
using namespace std;

namespace vbzIO {
    char ibuf[(1 << 20) + 1], *iS, *iT;
    #if ONLINE_JUDGE
    #define gh() (iS == iT ? iT = (iS = ibuf) + fread(ibuf, 1, (1 << 20) + 1, stdin), (iS == iT ? EOF : *iS++) : *iS++)
    #else
    #define gh() getchar()
    #endif
    #define mt make_tuple
    #define mp make_pair
    #define fi first
    #define se second
    #define pc putchar
    #define pb emplace_back
    #define ins insert
    #define era erase
    typedef tuple<int, int, int> tu3;
    typedef pair<int, int> pi;
    inline int rd() {
        char ch = gh();
        int x = 0;
        bool t = 0;
        while (ch < '0' || ch > '9') t |= ch == '-', ch = gh();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + (ch ^ 48), ch = gh();
        return t ? ~(x - 1) : x;
    }
    inline void wr(int x) {
        if (x < 0) x = ~(x - 1), putchar('-');
        if (x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
}
using namespace vbzIO;

const int N = 5e4 + 500;
const int P = 1e9 + 7;
const int i2 = (P + 1) / 2;

int n, m, a[2][N];

void Add(int &x, int y) { x += y; if (x >= P) x -= P; }
void Sub(int &x, int y) { x += P - y; if (x >= P) x -= P; }
int add(int x, int y) { return Add(x, y), x; }
int sub(int x, int y) { return Sub(x, y), x; }

int qpow(int p, int q) {
	int res = 1;
	for (; q; q >>= 1, p = p * p % P)
		if (q & 1) res = res * p % P;
	return res;
}

struct num {
	int x, y;
	num () { }
	num (int _x, int _y) : x(_x), y(_y) { }
	num operator + (const num &r) { return num(add(x, r.x), add(y, r.y)); }
	num operator - (const num &r) { return num(sub(x, r.x), sub(y, r.y)); }
	num operator += (const num &r) { Add(x, r.x), Add(y, r.y); return (*this); }
	num operator -= (const num &r) { Sub(x, r.x), Sub(y, r.y); return (*this); }
	num operator * (const num &r) { return num(add(x * r.x % P, 5 * y * r.y % P), add(y * r.x % P, x * r.y % P)); }
	num operator * (const int &r) { return num(x * r % P, y * r % P); }
	num inv() { return num(x, P - y) * qpow(add(x * x % P, (P - 5) * y % P * y % P), P - 2); }
} w[2], iw[2], pw[2][45], ipw[2][45];

void gts(num &p, num *s, int q) {
	for (int i = 0; (1ll << i) <= q; i++)
		if ((q >> i) & 1) p = p * s[i];
}

struct fib {
	num x, y;
	fib () { }
	fib (num _x, num _y) : x(_x), y(_y) { }
	void gt(int q) { return ((q > 0) ? (gts(x, pw[0], q), gts(y, pw[1], q)) : (gts(x, ipw[0], -q), gts(y, ipw[1], -q))), void(); }
	void init(int q) { x = num(1, 0), y = num(1, 0), gt(q); }
	fib operator + (const fib &r) { return fib(x + r.x, y + r.y); }
};

void init() {
	w[0] = num(i2, i2), w[1] = num(i2, P - i2);
	for (int i = 0; i <= 1; i++) {
		iw[i] = w[i].inv();
		pw[i][0] = w[i], ipw[i][0] = iw[i];
		for (int j = 1; j <= 40; j++)
			pw[i][j] = pw[i][j - 1] * pw[i][j - 1],
			ipw[i][j] = ipw[i][j - 1] * ipw[i][j - 1];
	}
}

struct seg {
	int mx[2], mn[2], lz[2];
	fib vl;
} tr[N << 2];

#define ls x << 1
#define rs x << 1 | 1
#define mid ((l + r) >> 1)

void ptg(seg &x, int c[2]) {
	if (!c[0] && !c[1]) return;
	for (int i = 0; i <= 1; i++) 
		x.lz[i] += c[i], x.mx[i] += c[i], x.mn[i] += c[i];
	x.vl.gt(c[0] + c[1]);
}

void pup(int x) {
	for (int i = 0; i <= 1; i++)
		tr[x].mx[i] = max(tr[ls].mx[i], tr[rs].mx[i]),
		tr[x].mn[i] = min(tr[ls].mn[i], tr[rs].mn[i]);
	tr[x].vl = tr[ls].vl + tr[rs].vl;
}

void pdn(int x) {
	ptg(tr[ls], tr[x].lz);
	ptg(tr[rs], tr[x].lz);
	tr[x].lz[0] = tr[x].lz[1] = 0;
}

void build(int l, int r, int x) {
	if (l == r) {
		for (int i = 0; i <= 1; i++)
			tr[x].mx[i] = tr[x].mn[i] = a[i][l];
		return tr[x].vl.init(a[0][l] + a[1][l]), void();
	}
	build(l, mid, ls), build(mid + 1, r, rs);
	pup(x);
}

void updmn(int l, int r, int s, int t, int op, int c, int x) {
	if (tr[x].mx[op] <= c) return;
	if (s <= l && r <= t && tr[x].mx[op] == tr[x].mn[op]) {
		int t[2]; t[op] = c - tr[x].mx[op], t[op ^ 1] = 0;
		return ptg(tr[x], t);
	}
	pdn(x);
	if (s <= mid) updmn(l, mid, s, t, op, c, ls);
	if (t > mid) updmn(mid + 1, r, s, t, op, c, rs);
	pup(x);
}

void updmx(int l, int r, int s, int t, int op, int c, int x) {
	if (tr[x].mn[op] >= c) return;
	if (s <= l && r <= t && tr[x].mx[op] == tr[x].mn[op]) {
		int t[2]; t[op] = c - tr[x].mx[op], t[op ^ 1] = 0;
		return ptg(tr[x], t);
	}
	pdn(x);
	if (s <= mid) updmx(l, mid, s, t, op, c, ls);
	if (t > mid) updmx(mid + 1, r, s, t, op, c, rs);
	pup(x);
}

void upd(int l, int r, int s, int t, int op, int c, int x) {
	if (s <= l && r <= t) {
		int t[2]; t[op] = c, t[op ^ 1] = 0;
		return ptg(tr[x], t); 
	}
	pdn(x);
	if (s <= mid) upd(l, mid, s, t, op, c, ls);
	if (t > mid) upd(mid + 1, r, s, t, op, c, rs);
	pup(x);
}

fib qry(int l, int r, int s, int t, int x) {
	if (s <= l && r <= t) return tr[x].vl;
	pdn(x);
	if (s > mid) return qry(mid + 1, r, s, t, rs);
	else if (t <= mid) return qry(l, mid, s, t, ls);
	return qry(l, mid, s, t, ls) + qry(mid + 1, r, s, t, rs);
}

signed main() {
	n = rd(), m = rd(), init();
	for (int i = 1; i <= n; i++) a[0][i] = rd();
	for (int i = 1; i <= n; i++) a[1][i] = rd();
	build(1, n, 1);
	while (m--) {
		int op = rd(), k, l, r, x; fib res;
		if (op == 1) k = rd() - 1, l = rd(), r = rd(), x = rd(), updmn(1, n, l, r, k, x, 1);
		else if (op == 2) k = rd() - 1, l = rd(), r = rd(), x = rd(), updmx(1, n, l, r, k, x, 1);
		else if (op == 3) k = rd() - 1, l = rd(), r = rd(), x = rd(), upd(1, n, l, r, k, x, 1);
		else l = rd(), r = rd(), res = qry(1, n, l, r, 1), wr((res.x - res.y).y), pc('\n');
	}
	return 0;
}