• 洛谷P5113 Sabbat of the witch


    题面

    题解

    分块,考虑用 vector 记下单点和整块被赋值的所有情况,同时对整块实时维护 ans。

    Part I. 块的构建/重构

    首先按照最后被修改的时间将块内的所有元素排序(注意如果要保证复杂度严格是 (mathcal O(n sqrt n)) 的话要用基数排序),维护当前的顺序信息,记录元素值的后缀和、当前最后一个整块赋值操作的时间 (mathrm {lst}_i) 和指针 (mathrm {pos}_i) 用来维护最后一个单点修改时间比整块修改时间小的位置,这样的话,整块的答案就是前 (mathrm{pos}_i) 个都是 (mathrm{lst}_i),而剩下的就是一个后缀和。

    Part II. 区间赋值

    散块暴力加了之后重构,整块直接更新答案。

    Part III. 撤销某一操作

    对当前操作打上 deleted 标记,弹出每个点和整块的 vector 的末尾直到末尾不再有标记,之后对散块重构。

    而对于整块,如果最后的整体赋值时间比上次重构时的 (mathrm{lst}) 要更大,说明整块赋值操作没有被撤销完,可以直接知道答案。

    否则可以知道删掉的操作一定是单调的,可以直接通过移动 (mathrm{pos}) 指针计算出答案。

    总时间复杂度 (mathcal O(n sqrt n))

    代码

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <vector>
    #define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
    
    inline int read()
    {
    	int data = 0, w = 1; char ch = getchar();
    	while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    	if (ch == '-') w = -1, ch = getchar();
    	while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
    	return data * w;
    }
    
    using ll = long long;
    const int N(1e5 + 10), sqrtN(500);
    struct node { int l, r, v; } q[N];
    int n, m, Len, a[N], del[N], bel[N], lst[sqrtN], pos[sqrtN], L[sqrtN], R[sqrtN];
    ll ans[sqrtN];
    std::vector<int> v[N], op[sqrtN];
    std::vector<int> num[sqrtN];
    std::vector<ll> sum[sqrtN];
    
    void Radix_Sort(const int &n, std::pair<int, int> *a)
    {
    	static int r1[256], r2[256];
    	static std::pair<int, int> b[sqrtN];
    	std::pair<int, int> *j, *tar; int i, tmp;
    	std::memset(r1, 0, sizeof r1), std::memset(r2, 0, sizeof r2);
    	for (j = a + 1, tar = a + n + 1; j != tar; j++)
    		tmp = j -> first, ++r1[tmp & 0xff], ++r2[(tmp >> 8) & 0xff];
    	for (i = 1; i < 256; i++) r1[i] += r1[i - 1], r2[i] += r2[i - 1];
    	for (j = a + n; j != a; j--) b[r1[(j -> first) & 0xff]--] = *j;
    	for (j = b + n; j != b; j--) a[r2[((j -> first) >> 8) & 0xff]--] = *j;
    }
    
    #define tim(i) (v[i].empty() ? 0 : v[i].back())
    #define val(i) (v[i].empty() ? a[i] : q[v[i].back()].v)
    void rebuild(int id)
    {
    	static std::pair<int, int> g[sqrtN]; int l = L[id], r = R[id], c = 0;
    	for (int i = l; i <= r; i++) g[++c] = std::make_pair(tim(i), i);
    	Radix_Sort(c, g), num[id].resize(c), sum[id].resize(c + 1);
    	for (int i = c - 1; i >= 0; i--)
    		num[id][i] = g[i + 1].second, sum[id][i] = sum[id][i + 1] + val(g[i + 1].second);
    	lst[id] = op[id].empty() ? 0 : op[id].back();
    	for (pos[id] = 0; pos[id] < c; pos[id]++) if (g[pos[id] + 1].first >= lst[id]) break;
    	--pos[id], ans[id] = 1ll * (pos[id] + 1) * q[lst[id]].v + sum[id][pos[id] + 1];
    }
    
    void Cover(int id)
    {
    	int l = q[id].l, r = q[id].r;
    	if (bel[l] == bel[r]) { for (int i = l; i <= r; i++) v[i].push_back(id); return rebuild(bel[l]); }
    	for (int i = l; bel[i] == bel[l]; i++) v[i].push_back(id); rebuild(bel[l]);
    	for (int i = r; bel[i] == bel[r]; i--) v[i].push_back(id); rebuild(bel[r]);
    	for (int i = bel[l] + 1; i < bel[r]; i++)
    		op[i].push_back(id), ans[i] = 1ll * (R[i] - L[i] + 1) * q[id].v;
    }
    
    ll Sum(int l, int r)
    {
    	ll ans = 0;
    #define do_node(x) ans += (tim(x) >= t ? val(x) : q[t].v)
    #define tblk(i) (op[i].empty() ? 0 : op[i].back())
    	if (bel[l] == bel[r]) { for (int i = l, t = tblk(bel[i]); i <= r; i++) do_node(i); return ans; }
    	for (int i = l, t = tblk(bel[i]); bel[i] == bel[l]; i++) do_node(i);
    	for (int i = r, t = tblk(bel[i]); bel[i] == bel[r]; i--) do_node(i);
    	for (int i = bel[l] + 1; i < bel[r]; i++) ans += ::ans[i];
    #undef tblk
    #undef do_node
    	return ans;
    }
    
    void Undo(int id)
    {
    	int l = q[id].l, r = q[id].r; del[id] = 1;
    #define do_node(x) while (!v[x].empty() && del[v[x].back()]) v[x].pop_back()
    	if (bel[l] == bel[r]) { for (int i = l; i <= r; i++) do_node(i); return rebuild(bel[l]); }
    	for (int i = l; bel[i] == bel[l]; i++) do_node(i); rebuild(bel[l]);
    	for (int i = r; bel[i] == bel[r]; i--) do_node(i); rebuild(bel[r]);
    	for (int i = bel[l] + 1; i < bel[r]; i++)
    	{
    		while (!op[i].empty() && del[op[i].back()]) op[i].pop_back();
    		int t = op[i].empty() ? 0 : op[i].back();
    		if (t > lst[i]) ans[i] = 1ll * (R[i] - L[i] + 1) * q[t].v;
    		else
    		{
    			while (pos[i] >= 0 && tim(num[i][pos[i]]) >= t) --pos[i];
    			ans[i] = 1ll * (pos[i] + 1) * q[t].v + sum[i][pos[i] + 1];
    		}
    	}
    #undef do_node
    }
    
    int main()
    {
    #ifndef ONLINE_JUDGE
    	file(cpp);
    #endif
    	Len = std::sqrt(n = read()), m = read();
    	for (int i = 1; i <= n; i++) a[i] = read();
    	for (int i = 1; i <= n; i++) bel[i] = (i - 1) / Len + 1;
    	for (int i = 1; i <= n; i++) R[bel[i]] = i;
    	for (int i = n; i; i--) L[bel[i]] = i;
    	for (int i = 1; i <= bel[n]; i++) rebuild(i);
    	int cnt = 0; ll ans = 0;
    	while (m--)
    	{
    		int op = read(), l, r;
    		if (op == 1) q[++cnt] = (node) {read() ^ ans, read() ^ ans, read()}, Cover(cnt);
    		else if (op == 2) l = read() ^ ans, r = read() ^ ans, printf("%lld
    ", ans = Sum(l, r));
    		else Undo(read() ^ ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    安装minio单机
    linux使用某非root用户执行开机启动项
    Maven Plugin fork 在 pom.xml中的作用
    Sourcetree 使用之 git add, git commit, git push, git reset commit
    idea远程debug k8s容器服务
    WebService Client端
    Maven编译外部jar包问题
    Sourcetree 使用之 git stash save 和 git stash pop
    Sybase 相关
    FW300R手机不能上网解决方法
  • 原文地址:https://www.cnblogs.com/cj-xxz/p/14415375.html
Copyright © 2020-2023  润新知