zoukankan      html  css  js  c++  java
  • 「Luogu P2042」「NOI2005」维护数列

    Description

    请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线‘ _ ’表示实际输入文件中的空格)

    (N) 表示初始时数列中数的个数,(M) 表示要进行的操作数目。

    Hint

    任何时刻数列中最多含有 (5 imes 10^5) 个数。

    任何时刻数列中任何一个数字均在 ([-10^3,10^3]) 内。

    (1le Mle 2 imes 10^4) ,插入的数字总数不超过 (4 imes 10^6)

    Solution

    这个可以说是 Splay 维护数列的板题了。用 Splay 作为区间树,关键字可以理解为 位置

    首先建树,加入虚拟结点,放置某些时候操作到边上是出现一些奇奇怪怪的错误。

    先扯一下 Splay 做简单区间操作的一些套路—— 子树提取

    假设要提取区间 ([l, r]),那么只要找到第 (l) 个和第 (r + 2) 个结点(原来是第 (l-1, r+1) 个,但是要注意最开头有一个虚拟结点),令其分别为结点 (x, y)

    接下来直接 splay(x, 0), splay(r, l),就行了,结点 (y) 的左子树即为所求区间对应的子树的根:

    Yhk9oj.png

    然后,一个个操作来。

    INSERT 操作

    找到要插入的位置左边、右边的两个结点(注意有虚拟结点,需要 +1)。

    然后两个结点上旋。

    将插入数列建好树,之后在根的右儿子的左儿子的位置处插入建好的树。

    最后 maintain 一下。

    DELETE 操作

    找到待删除数列的端点的 左/右一个位置 的结点,上旋。

    使用一个垃圾回收机制,存下删掉的结点,等到重新建树时用。

    ch[r][0] ← 0,maintain。

    MAKE-SAME 操作

    找到待修改区间的端点的 左/右一个位置 的结点,上旋。

    打一个标记,maintain。

    REVERSE 操作

    找到待修改区间的端点的 左/右一个位置 的结点,上旋。

    打一个标记,maintain。

    GET-SUM 操作

    维护一个子树值和。

    找到目标区间的端点的 左/右一个位置 的结点,上旋。

    获取 sum 返回。

    MAX-SUM 操作

    有点麻烦,套路就是 GSS 的差不多。

    维护一个最大前缀和,最大后缀和,最大子段和。

    具体见代码。

    时间复杂度 (O(nlog n)),空间复杂度 (O(n))

    坑点

    最大子段和的子段必须至少选一个元素。

    题目给的参数意义有点区别。

    先将 0 号结点初始化一下。

    Code

    /*
     * Author : _Wallace_
     * Source : https://www.cnblogs.com/-Wallace-/
     * Problem : Luogu P2042 NOI2005 维护数列
     */
    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <stack>
    using namespace std;
    
    const int N = 5e5 + 5;
    const long long inf = 1e18;
    typedef long long LL;
    
    int ch[N][2], fa[N], size[N];
    LL val[N], sum[N], lmax[N], rmax[N], mmax[N];
    bool cov[N], rev[N];
    
    LL ary[N];
    int n, q, total = 0, root;
    stack<int> rec;
    
    inline int create() {
    	if (rec.empty()) return ++total;
    	int ret = rec.top();
    	return rec.pop(), ret;
    }
    inline void clear(int rt) {
    	ch[rt][0] = ch[rt][1] = fa[rt] = 0;
    	val[rt] = lmax[rt] = rmax[rt] = 0;
    	mmax[rt] = -inf;
    	cov[rt] = rev[rt] = 0;
    }
    
    inline void maintain(int rt) {
    	size[rt] = size[ch[rt][0]] + size[ch[rt][1]] + 1;
    	sum[rt] = sum[ch[rt][0]] + sum[ch[rt][1]] + val[rt];
    	lmax[rt] = max(lmax[ch[rt][0]], lmax[ch[rt][1]] + sum[ch[rt][0]] + val[rt]);
    	rmax[rt] = max(rmax[ch[rt][1]], rmax[ch[rt][0]] + sum[ch[rt][1]] + val[rt]);
    	mmax[rt] = max(max(mmax[ch[rt][0]], mmax[ch[rt][1]]), lmax[ch[rt][1]] + rmax[ch[rt][0]] + val[rt]);
    }
    inline void pushdown(int rt) {
    	int &l = ch[rt][0], &r = ch[rt][1];
    	if (cov[rt]) {
    		rev[rt] = cov[rt] = 0;
    		if (l) cov[l] = 1, val[l] = val[rt], sum[l] = val[rt] * size[l];
    		if (r) cov[r] = 1, val[r] = val[rt], sum[r] = val[rt] * size[r];
    		if (val[rt] >= 0) {
    			if (l) lmax[l] = rmax[l] = mmax[l] = sum[l];
    			if (r) lmax[r] = rmax[r] = mmax[r] = sum[r];
    		} else {
    			if (l) lmax[l] = rmax[l] = 0, mmax[l] = val[l];
    			if (r) lmax[r] = rmax[r] = 0, mmax[r] = val[r];
    		}
    	}
    	if (rev[rt]) {
    		rev[rt] = 0;
    		if (l) rev[l] ^= 1;
    		if (r) rev[r] ^= 1;
    		swap(lmax[l], rmax[l]);
    		swap(lmax[r], rmax[r]);
    		swap(ch[l][0], ch[l][1]);
    		swap(ch[r][0], ch[r][1]);
    	}
    }
    
    inline int get(int rt) {
    	return rt == ch[fa[rt]][1];
    }
    inline void rotate(int x) {
    	int y = fa[x], z = fa[y], c = get(x);
    	ch[y][c] = ch[x][c ^ 1];
    	fa[ch[x][c ^ 1]] = y;
    	ch[x][c ^ 1] = y;
    	fa[y] = x, fa[x] = z;
    	if (z) ch[z][y == ch[z][1]] = x;
    	maintain(y), maintain(x);
    }
    inline void splay(int x,int g) {
    	for (register int f = fa[x]; (f = fa[x]) != g; rotate(x))
    		if(fa[f] != g) rotate(get(f) == get(x) ? f : x);
    	if (!g) root = x;
    }
    
    inline int select(int k) {
    	for (register int rt = root; rt;) {
    		pushdown(rt);
    		if (k == size[ch[rt][0]] + 1) return rt;
    		if (k < size[ch[rt][0]] + 1) rt = ch[rt][0];
    		else k -= size[ch[rt][0]] + 1, rt = ch[rt][1];
    	}
    	throw;
    }
    int build(int l, int r, int f) {
    	if (l>r) return 0;
    	int rt = create(), mid = (l + r) >> 1;
    	if (l == r) {
    		val[rt] = sum[rt] = ary[mid];
    		size[rt] = 1;
    		ch[rt][0] = ch[rt][1] = 0;
    		fa[rt] = f;
    		lmax[rt] = rmax[rt] = max(0ll, val[rt]);
    		mmax[rt] = val[rt];
    		return rt;
    	}
    	val[rt] = ary[mid], fa[rt] = f;
    	ch[rt][0] = build(l, mid - 1, rt);
    	ch[rt][1] = build(mid + 1, r, rt);
    	return maintain(rt), rt;
    }
    
    inline void insert(int pos, int tot) {
    	if (!tot) return;
    	int l = select(pos + 1), r = select(pos + 2);
    	splay(l, 0), splay(r, l);
    	ch[r][0] = build(1, tot, r);
    	maintain(r), maintain(l);
    }
    
    void recycle(int rt) {
    	if (!rt) return;
    	rec.push(rt);
    	recycle(ch[rt][0]);
    	recycle(ch[rt][1]);
    	clear(rt);
    }
    inline void erase(int pos, int tot) {
    	if (!tot) return;
    	int l = select(pos), r = select(pos + tot + 1);
    	splay(l, 0), splay(r, l);
    	recycle(ch[r][0]), ch[r][0] = 0;
    	maintain(r), maintain(l);
    }
    
    inline void assign(int pos, int tot, LL c) {
    	if (!tot) return;
    	int l = select(pos), r = select(pos + tot + 1);
    	splay(l, 0), splay(r, l);
    	int x = ch[r][0];
    	val[x] = c, sum[x] = size[x] * c;
    	if (c >= 0) lmax[x] = rmax[x] = mmax[x] = sum[x];
    	else lmax[x] = rmax[x] = 0, mmax[x] = val[x];
    	cov[x] = 1;
    	maintain(r), maintain(l);
    }
    
    inline void reverse(int pos, int tot) {
    	if (!tot) return;
    	int l = select(pos), r = select(pos + tot + 1);
    	splay(l, 0), splay(r, l);
    	int x = ch[r][0];
    	if (cov[x]) return;
    	swap(ch[x][0], ch[x][1]);
    	swap(lmax[x], rmax[x]);
    	rev[x] ^= 1;
    	maintain(r), maintain(l);
    }
    
    inline LL getSum(int pos, int tot) {
    	if (!tot) return 0ll;
    	int l = select(pos), r = select(pos + tot + 1);
    	splay(l, 0), splay(r, l);
    	return sum[ch[r][0]];
    }
    inline LL getMaxSum() {
    	int l = select(1), r = select(size[root]);
    	splay(l, 0), splay(r, l);
    	return mmax[ch[r][0]];
    }
    
    signed main() {
    	ios::sync_with_stdio(0);
    	cin >> n >> q;
    	
    	for (register int i = 1; i <= n; i++)
    		cin >> ary[i + 1];
    	ary[1] = ary[n + 2] = -inf;
    	
    	clear(0);
    	root = build(1, n + 2, 0);
    	
    	while (q--) {
    		string cmd;
    		int pos, tot;
    		LL c;
    		
    		cin >> cmd;
    		if (cmd == "INSERT") {
    			cin >> pos >> tot;
    			for (register int i = 1; i <= tot; i++)	
    				cin >> ary[i];
    			insert(pos, tot);
    		}
    		if (cmd == "DELETE") {
    			cin >> pos >> tot;
    			erase(pos, tot);
    		}
    		if (cmd == "MAKE-SAME") {
    			cin >> pos >> tot >> c;
    			assign(pos, tot, c);
    		}
    		if (cmd == "REVERSE") {
    			cin >> pos >> tot;
    			reverse(pos, tot);
    		}
    		if (cmd == "GET-SUM") {
    			cin >> pos >> tot;
    			cout << getSum(pos, tot) << endl;
    		}
    		if (cmd == "MAX-SUM")
    			cout << getMaxSum() << endl;
    	}
    }
    
  • 相关阅读:
    当spfile文件中的参数修改错误,导致数据库无法启动问题
    oracle的shared server模式和dedicated server模式
    概述oracle的内存结构
    oracle进程简介
    TNS12516及ORA12516错误解决
    如何打补丁及升级
    关于sqlplus的简单概述
    修改参数之后数据库无法启动问题
    oracle的后台进程杀掉会有什么影响
    远程连接oracle数据库ORA12154错误
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/12674103.html
Copyright © 2011-2022 走看看