zoukankan      html  css  js  c++  java
  • 「HNOI2011」「JSOI2011」「Luogu P3215」 括号修复 / 括号序列

    Description

    一个合法的括号序列是这样定义的:

    • 空串是合法的。
    • 如果字符串 S 是合法的,则 (S) 也是合法的。
    • 如果字符串 AB 是合法的,则 AB 也是合法的。

    现在给你一个长度为 (n) 的由 () 组成的字符串,位置标号从 (1)(n) 。对这个字符串有下列四种操作:

    Replace a b c:将 ([a,b]) 之间的所有括号改成 (c)。假设原来的字符串为:))())())(,那么执行操作 Replace 2 7 后原来的字符串变为:)(((((()(

    Swap a b:将 ([a,b]) 之间的字符串翻转。假设原来的字符串为:))())())(,那么执行操作 Swap 3 5 后原来的字符串变为:))))(())(

    Invert a b:将 ([a,b]) 之间的 ( 变成 )) 变成 (。假设原来的字符串为:))())())(,那么执行操作 Invert 4 8 后原来的字符串变为:))((()(((

    Query a b:询问 ([a,b]) 之间的字符串至少要改变多少位才能变成合法的括号序列。改变某位是指将该位的 ( 变成 )) 变成 (。注意执行操作 Query 并不改变当前的括号序列。假设原来的字符串为:))())())(,那么执行操作 Query 3 6 的结果为 (2),因为要将位置 (5)) 变成 ( 并将位置 (6)( 变成 )

    现给定 (n) 和这个字符串,以及 (q) 个操作,对于某一个 Query 询问输出答案。

    Hint

    (1le n,qle 10^5)

    Solution

    首先考虑一下如果做 Query 操作。

    假如说,字符串为 ))())())((,那么配对的左右括号相互抵消,那么就成了:))))((

    若要将其改为合法的括号序列,显然要改成这样:(())(),一共改了 2 个 ( ,一个 )。可见是大概一般的左括号和右括号被修改了。

    直接说结论:设 ( exttt{'('} = -1, exttt{')'} = 1),令 ( ext{lmax, rmax, lmin, rmin}) 分别为最大前后缀和、最小前后缀和。

    那么 ( ext{Query}(l, r) = leftlceil{ ext{lmax}(l, r) / 2} ight ceil + leftlceil{| ext{rmin}(l, r)| / 2} ight ceil) ,注意向上取整,以及最小后缀和需要取绝对值。

    另外两个 ( ext{rmax, lmin}) 是辅助维护的,具体方法参考 SPOJ - GSS 系列题目。

    如果没有 区间反转 可以 线段树,但现在只能 平衡树 了。时间复杂度 (O(nlog n))

    下面是代码,把更新信息的操作写在函数里了,看得轻松一点。

    Code

    /*
     * Author : _Wallace_
     * Source : https://www.cnblogs.com/-Wallace-/
     * Problem : HNOI2011 JSOI2011 Luogu P3215 括号修复 / 括号序列
     */
    #include <iostream>
    #include <cmath>
    #include <string>
    using namespace std;
    
    const int N = 1e5 + 5;
    int n, q;
    
    int ch[N][2], fa[N], size[N];
    int total = 0, root;
    
    int lmax[N], rmax[N];
    int lmin[N], rmin[N];
    int sum[N], val[N];
    
    int cov[N];
    bool rev[N], flip[N]; 
    
    inline int create(int c) {
    	int rt = ++ total;
    	val[rt] = sum[rt] = c;
    	size[rt] = 1;
    	if (c >= 0) {
    		lmax[rt] = rmax[rt] = c;
    		lmin[rt] = rmin[rt] = 0;
    	} else {
    		lmin[rt] = rmin[rt] = c;
    		lmax[rt] = rmax[rt] = 0;
    	}
    	return rt;
    }
    
    inline void pushup(int rt) {
    	int &l = ch[rt][0], &r = ch[rt][1];
    	sum[rt] = sum[l] + sum[r] + val[rt];
    	size[rt] = size[l] + size[r] + 1;
    	lmax[rt] = max(lmax[l], sum[l] + val[rt] + lmax[r]);
    	rmax[rt] = max(rmax[r], sum[r] + val[rt] + rmax[l]);
    	lmin[rt] = min(lmin[l], sum[l] + val[rt] + lmin[r]);
    	rmin[rt] = min(rmin[r], sum[r] + val[rt] + rmin[l]);
    }
    
    inline void updateRev(int rt) {
    	int &l = ch[rt][0], &r = ch[rt][1];
    	swap(l, r);
    	swap(lmax[rt], rmax[rt]);
    	swap(lmin[rt], rmin[rt]);
    	rev[rt] ^= 1;
    }
    inline void updateCov(int rt, int c)  {
    	val[rt] = c, sum[rt] = c * size[rt];
    	if (c >= 0) {
    		lmin[rt] = rmin[rt] = 0;
    		lmax[rt] = rmax[rt] = sum[rt];
    	} else {
    		lmax[rt] = rmax[rt] = 0;
    		lmin[rt] = rmin[rt] = sum[rt];
    	}
    	cov[rt] = c;
    }
    inline void updateFlip(int rt) {
    	val[rt] = -val[rt], sum[rt] = -sum[rt];
    	int temp = lmax[rt];
    	lmax[rt] = -lmin[rt];
    	lmin[rt] = -temp;
    	temp = rmax[rt];
    	rmax[rt] = -rmin[rt];
    	rmin[rt] = -temp;
    	flip[rt] ^= 1;
    	cov[rt] = -cov[rt];
    }
    inline void pushdown(int rt) {
    	int &l = ch[rt][0], &r = ch[rt][1];
    	if (flip[rt]) {
    		if (l) updateFlip(l);
    		if (r) updateFlip(r);
    		flip[rt] = 0;
    	}
    	if (cov[rt]) {
    		if (l) updateCov(l, cov[rt]);
    		if (r) updateCov(r, cov[rt]);
    		cov[rt] = 0;
    	}
    	if (rev[rt]) {
    		if (l) updateRev(l);
    		if (r) updateRev(r);
    		rev[rt] = 0;
    	}
    }
    
    inline int get(int x) {
    	return x == ch[fa[x]][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;
    	pushup(y), pushup(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; ; ) {
    		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];
    	}
    }
    int ary[N];
    int build(int l, int r, int f) {
    	if (l > r) return 0;
    	int mid = (l + r) >> 1, rt = create(ary[mid]);
    	val[rt] = ary[mid], fa[rt] = f;
    	ch[rt][0] = build(l, mid - 1, rt);
    	ch[rt][1] = build(mid + 1, r, rt);
    	return pushup(rt), rt;
    }
    
    inline void replace(int l, int r, int c) {
    	l = select(l), r = select(r + 2);
    	splay(l, 0), splay(r, l);
    	int x = ch[r][0];
    	updateCov(x, c);
    	pushup(r), pushup(l);
    }
    inline void reverse(int l, int r) {
    	l = select(l), r = select(r + 2);
    	splay(l, 0), splay(r, l);
    	int x = ch[r][0];
    	updateRev(x);
    	pushup(r), pushup(l);
    }
    inline void invert(int l, int r) {
    	l = select(l), r = select(r + 2);
    	splay(l, 0), splay(r, l);
    	int x = ch[r][0];
    	updateFlip(x);
    	pushup(r), pushup(l);
    }
    inline int query(int l, int r) {
    	l = select(l), r = select(r + 2);
    	splay(l, 0), splay(r, l);
    	int x = ch[r][0];
    	int p = lmax[x];
    	p = (p & 1) ? (p + 1) / 2 : p / 2;
    	int s = abs(rmin[x]);
    	s = (s & 1) ? (s + 1) / 2 : s / 2;
    	return p + s;
    }
    
    signed main() {
    	ios::sync_with_stdio(false);
    	int n, q; string s;
    	cin >> n >> q >> s;
    	for (register int i = 1; i <= n; i ++)
    		ary[i + 1] = (s[i - 1] == '(') ? -1 : 1;
    	
    	ary[1] = ary[n + 2] = 0;
    	root = build(1, n + 2, 0);
    	
    	while (q --) {
    		int l, r;
    		cin >> s;
    		
    		if (s == "Replace") {
    			cin >> l >> r >> s;
    			replace(l, r, (s == "(") ? -1 : 1);
    		}
    		if (s == "Swap") {
    			cin >> l >> r;
    			reverse(l, r);
    		}
    		if (s == "Invert") {
    			cin >> l >> r;
    			invert(l, r);
    		}
    		if (s == "Query") {
    			cin >> l >> r;
    			cout << query(l, r) << '
    ';
    		}
    	}
    }
    
  • 相关阅读:
    四则运算---3
    四则运算---2
    四则运算---1
    我的软工实践总结
    用例图练习..................................................
    第四次作业——个人作业——软件案例分析
    第三次作业——将排课Excel导入系统
    第二次作业——结对项目之需求分析与原型模型设计
    软工实践练习一(个人)----将Androidstudio的项目共享到github
    第一次作业---安卓开发工具Android studio发展演变
  • 原文地址:https://www.cnblogs.com/-Wallace-/p/12775785.html
Copyright © 2011-2022 走看看