P7497 四方喝彩 Solution

Description

给定序列 a=(a1,a2,⋯ ,an)a=(a_1,a_2,\cdots,a_n)a=(a1,a2,,an),有 mmm 个操作,分四种:

  • add⁡(l,r,v)\operatorname{add}(l,r,v)add(l,r,v):对于所有 i∈[l,r]i \in [l,r]i[l,r] 执行 ai←ai+va_i \gets a_i+vaiai+v.
  • mul⁡(l,r,v)\operatorname{mul}(l,r,v)mul(l,r,v):对于所有 i∈[l,r]i \in [l,r]i[l,r] 执行 ai←ai×va_i \gets a_i\times vaiai×v.
  • freeze⁡(l,r,x)\operatorname{freeze}(l,r,x)freeze(l,r,x):区间 [l,r][l,r][l,r] 在接下来的 xxx 次操作中被冻结,不会受修改操作影响,已有的冻结效果不会被替换.
  • query⁡(l,r)\operatorname{query}(l,r)query(l,r):求 (∑i=lrai) mod (109+7)(\sum\limits_{i=l}^r a_i) \bmod (10^9+7)(i=lrai)mod(109+7).

Limitations

1≤n,m≤2×1051 \le n,m \le 2\times 10^51n,m2×105
0≤ai,v≤109+70 \le a_i,v \le 10^9+70ai,v109+7
设当前为第 ttt 次操作,则 0≤x≤m−k0 \le x \le m-k0xmk
1s,512MB1\text{s},512\text{MB}1s,512MB

Solution

freeze⁡\operatorname{freeze}freeze 操作拆成冻结和解冻两个操作,将解冻操作按解冻时间记在邻接表上.
考虑 add⁡\operatorname{add}add,由于区间可能部分冻结,故乘的长度不是 (r−l+1)(r-l+1)(rl+1) 而是未封锁元素个数,需要维护.
考虑 mul⁡\operatorname{mul}mul,同样由于区间可能部分冻结,不能直接 ×v\times v×v,而是将未冻结部分 ×v\times v×v,所以需要分开维护未冻结部分和冻结部分的和.
考虑多个冻结操作重叠,由于合并它们很麻烦,所以直接叠加,等到完全解冻才继续 pushdown,所以维护的是冻结次数而不是是否冻结
写的时候注意细节,具体可以看代码。

Code

7.96KB,1.06s,19.16MB  (in total, C++20 with O2)7.96\text{KB},1.06\text{s},19.16\text{MB}\;\texttt{(in total, C++20 with O2)}7.96KB,1.06s,19.16MB(in total, C++20 with O2)

// Problem: P7497 四方喝彩
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P7497
// Memory Limit: 512 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

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

using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;

template<class T>
bool chmax(T &a, const T &b){
	if(a < b){ a = b; return true; }
	return false;
}

template<class T>
bool chmin(T &a, const T &b){
	if(a > b){ a = b; return true; }
	return false;
}

template <int MOD>
struct modint {
    int val;
    static int norm(const int& x) { return x < 0 ? x + MOD : x; }
    modint inv() const {
        int a = val, b = MOD, u = 1, v = 0, t;
        while (b > 0) t = a / b, swap(a -= t * b, b), swap(u -= t * v, v);
        return modint(u);
    }
    modint() : val(0) {}
    modint(const int& m) : val(norm(m % MOD)) {}
    modint(const long long& m) : val(norm(m % MOD)) {}
    modint operator-() const { return modint(norm(-val)); }
    bool operator==(const modint& o) { return val == o.val; }
    bool operator!=(const modint &o) { return val != o.val; }
    bool operator<(const modint& o) { return val < o.val; }
    bool operator>(const modint& o) { return val > o.val; }
    bool operator<=(const modint& o) { return val <= o.val; }
    bool operator>=(const modint& o) { return val >= o.val; }
    modint& operator++() { return *this += 1; }
    modint operator++(int) { modint temp = *this; ++(*this); return temp; }
    modint& operator--() { return *this -= 1; }
    modint operator--(int) { modint temp = *this; --(*this); return temp; }
    modint& operator+=(const modint& o) { return val = (1ll * val + o.val) % MOD, *this; }
    modint& operator-=(const modint& o) { return val = norm(1ll * val - o.val), *this; }
    modint& operator*=(const modint& o) { return val = static_cast<int>(1ll * val * o.val % MOD), *this; }
    modint& operator/=(const modint& o) { return *this *= o.inv(); }
    modint& operator^=(const modint& o) { return val ^= o.val, *this; }
    modint& operator>>=(const modint& o) { return val >>= o.val, *this; }
    modint& operator<<=(const modint& o) { return val <<= o.val, *this; }
    modint operator-(const modint& o) const { return modint(*this) -= o; }
    modint operator+(const modint& o) const { return modint(*this) += o; }
    modint operator*(const modint& o) const { return modint(*this) *= o; }
    modint operator/(const modint& o) const { return modint(*this) /= o; }
    modint operator^(const modint& o) const { return modint(*this) ^= o; }
    modint operator>>(const modint& o) const { return modint(*this) >>= o; }
    modint operator<<(const modint& o) const { return modint(*this) <<= o; }
    friend std::istream& operator>>(std::istream& is, modint& a) {
        long long v;
        return is >> v, a.val = norm(v % MOD), is;
    }
    friend std::ostream& operator<<(std::ostream& os, const modint& a) { return os << a.val; }
    friend std::string tostring(const modint& a) { return std::to_string(a.val); }
    template <class T>
    friend modint qpow(const modint& a, const T& b) {
        modint x = a, res = 1;
        for (T p = b; p; x *= x, p >>= 1)
            if (p & 1) res *= x;
        return res;
    }
};

using Z = modint<1000000007>;

namespace seg_tree {
	struct Node {
	    int l, r, size, blocks;
	    Z sum_a, sum_b, add, mul;
	};
	
	inline int ls(int u) { return u * 2 + 1; }
	inline int rs(int u) { return u * 2 + 2; }
	
	struct SegTree {
		vector<Node> tr;
		inline SegTree() {}
		inline SegTree(const vector<int>& a) {
			const int n = a.size();
			tr.resize(n << 1);
			build(0, 0, n - 1, a);
		}
		
		inline void pushup(int u, int mid) {
		    if (tr[u].blocks == 0) {
		        tr[u].sum_a = tr[ls(mid)].sum_a + tr[rs(mid)].sum_a;
		        tr[u].sum_b = tr[ls(mid)].sum_b + tr[rs(mid)].sum_b;
		        tr[u].size = tr[ls(mid)].size + tr[rs(mid)].size;
		    }
		}
		
		inline void apply(const Node& rt, Node& son) {
		    if (son.blocks == 0) {
		        son.sum_a = son.sum_a * rt.mul + rt.add * son.size;
		        son.add = son.add * rt.mul + rt.add;
		        son.mul *= rt.mul;
		    }
		}
		
		inline void pushdown(int u, int mid) {
		    apply(tr[u], tr[ls(mid)]);
		    apply(tr[u], tr[rs(mid)]);
		    tr[u].add = 0;
		    tr[u].mul = 1;
		}
		
		void build(int u, int l, int r, const vector<int>& a) {
		    tr[u].l = l;
		    tr[u].r = r;
		    tr[u].mul = 1;
		    tr[u].add = 0;
		    if (l == r) {
		        tr[u].sum_a = a[l];
		        tr[u].size = 1;
		        return;
		    }
		    const int mid = (l + r) >> 1;
		    build(ls(mid), l, mid, a);
		    build(rs(mid), mid + 1, r, a);
		    pushup(u, mid);
		}
		
		void add(int u, int l, int r, const Z& val) {
		    if (tr[u].blocks > 0) return;
		    if (l <= tr[u].l && tr[u].r <= r) {
		        tr[u].sum_a += val * tr[u].size;
		        tr[u].add += val;
		        return;
		    }
		    const int mid = (tr[u].l + tr[u].r) >> 1;
		    pushdown(u, mid);
		    if (l <= mid) add(ls(mid), l, r, val);
		    if (r > mid) add(rs(mid), l, r, val);
		    pushup(u, mid);
		}
		
		void mul(int u, int l, int r, const Z& val) {
		    if (tr[u].blocks > 0) return;
		    if (l <= tr[u].l && tr[u].r <= r) {
		        tr[u].sum_a *= val;
		        tr[u].add *= val;
		        tr[u].mul *= val;
		        return;
			}
		    const int mid = (tr[u].l + tr[u].r) >> 1;
		    pushdown(u, mid);
		    if (l <= mid) mul(ls(mid), l, r, val);
		    if (r > mid) mul(rs(mid), l, r, val);
		    pushup(u, mid);
		}
		
		void block(int u, int l, int r) {
			const int mid = (tr[u].l + tr[u].r) >> 1;
		    if (l <= tr[u].l && tr[u].r <= r) {
		        if (tr[u].l < tr[u].r) pushdown(u, mid);
		        if (tr[u].blocks == 0) {
		            tr[u].sum_b += tr[u].sum_a;
		            tr[u].sum_a = 0;
		            tr[u].size = 0;
		        }
		        tr[u].blocks++;
		        return;
			}
		    pushdown(u, mid);
		    if (l <= mid) block(ls(mid), l, r);
		    if (r > mid) block(rs(mid), l, r);
		    pushup(u, mid);
		}
		
		void unblock(int u, int l, int r) {
			const int mid = (tr[u].l + tr[u].r) >> 1;
		    if (l <= tr[u].l && tr[u].r <= r) {
		        tr[u].blocks--;
		        if (tr[u].blocks == 0) {
		            if (tr[u].l == tr[u].r) {
		                tr[u].sum_a += tr[u].sum_b;
		                tr[u].sum_b = 0;
		                tr[u].size = 1;
		            }
		            else pushup(u, mid);
		        }
		        return;
		    }
		    pushdown(u, mid);
		    if (l <= mid) unblock(ls(mid), l, r);
		    if (r > mid) unblock(rs(mid), l, r);
		    pushup(u, mid);
		}
		
		Z query(int u, int l, int r) {
		    if (l <= tr[u].l && tr[u].r <= r) return tr[u].sum_a + tr[u].sum_b;
		    const int mid = (tr[u].l + tr[u].r) >> 1;
		    Z ans = 0;
		    pushdown(u, mid);
		    if (l <= mid) ans += query(ls(mid), l, r);
		    if (r > mid) ans += query(rs(mid), l, r);
		    return ans;
		}
		
		inline void range_add(int l, int r, const Z& v) { add(0, l, r, v); }
		inline void range_mul(int l, int r, const Z& v) { mul(0, l, r, v); }
		inline void range_block(int l, int r) { block(0, l, r); }
		inline void range_unblock(int l, int r) { unblock(0, l, r); }
		inline Z range_sum(int l, int r) { return query(0, l, r); }
	};
}
using seg_tree::SegTree;

signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0), cout.tie(0);
	
	int n, m;
	scanf("%d%d", &n, &m);
	
	vector<int> a(n);
	for (int i = 0; i < n; i++) scanf("%d", &a[i]);
	
	vector<vector<pair<int, int>>> blocks(m);
	SegTree sgt(a);
	for (int i = 0, op, l, r, v; i < m; i++) {
	    scanf("%d%d%d", &op, &l, &r), l--, r--;
	    if (op == 1) {
	        scanf("%d", &v);
	        sgt.range_add(l, r, Z(v));
	    }
	    if (op == 2) {
	        scanf("%d", &v);
	        sgt.range_mul(l, r, Z(v));
	    }
	    if (op == 3) {
	        scanf("%d", &v);
	        sgt.range_block(l, r);
	        blocks[i + v].emplace_back(l, r);
	    }
	    if (op == 4) printf("%d\n", sgt.range_sum(l, r).val);
	    for (auto [L, R] : blocks[i]) sgt.range_unblock(L, R);
	}
	
	return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值