【bzoj2329】[HNOI2011]括号修复
2017-04-01 11:34
375 查看
Description
一个合法的括号序列是这样定义的:1.空串是合法的。
2.如果字符串 S 是合法的,则(S)也是合法的。
3.如果字符串 A 和 B 是合法的,则 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 的‘(’变成‘)’。
Input
从文件input.txt中读入数据,输入文件的第一行是用空格隔开的两个正整数N和M,分别表示字符串的长度和将执行的操作个数。第二行是长度为N的初始字符串S。接下来的M行是将依次执行的M个操作,其中操作名与操作数之间以及相邻操作数之间均用空格隔开。30%的数据满足N,M≤3000。100%的数据满足N,M≤100000。Output
输出文件 output.txt 包含 T 行,其中 T 是输入的将执行的 M 个操作中 Query 操作出现的次数。Query 操作的每次出现依次对应输出文件中的一行,该行只有一个非负整数,表示执行对应 Query 操作的结果,即:所指字符串至少要改变多少位才能变成合法的括号序列。输入数据保证问题有解。Sample Input
4 5((((
Replace 1 2 )
Query 1 2
Swap 2 3
Invert 3 4
Query 1 4
Sample Output
12
题解
能够1A这题还是很开心的,虽然我写了一个早上。传送门:http://www.cnblogs.com/oldmanren/archive/2011/11/24/2262178.html一个写得十分清楚的题解。
简单来说Replace,Swap和Invert都是经典的splay操作。而Query可以转换为区间左起最小值和右起最大值的查询。
但是标记的下传也并没有那么麻烦。考虑对一段区间进行Replace操作,那么之前这段区间上的Swap和Invert操作的标记都会失效,我们可以直接将它们清零。那么对于一个节点上的标记,Replace操作的标记必然是最先操作的,那么首先将它下传,然后Swap操作的标记和Invert操作的标记就可以任意顺序下传了。
(发现我的程序还是算蛮短的233)
#include<bits/stdc++.h> using namespace std; const int N = 100000 + 10; inline int read(){ int x = 0, f = 1; char c = getchar(); while(!isdigit(c)) { if(c == '-') f = -1; c = getchar(); } while(isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); } return x * f; } int n, m; struct Splay{ int num, sum, _cov, _flip, _rev, siz; int lmx, lmn, rmx, rmn; Splay *fa, *ch[2]; int d(){return fa->ch[1] == this;} void sc(Splay *a, int d){(ch[d] = a)->fa = this;} void cov(int x){ sum = x * siz; num = x; if(x == 1) lmx = rmx = sum, lmn = rmn = 0; else lmn = rmn = sum, lmx = rmx = 0; _cov = x; _rev = _flip = 0; } void rev(){ swap(lmx, rmx); swap(lmn, rmn); swap(ch[0], ch[1]); _rev ^= 1; } void flip(){ sum *= -1; num *= -1; swap(lmx, lmn); swap(rmx, rmn); lmx *= -1, lmn *= -1, rmx *= -1, rmn *= -1; _flip ^= 1; } void pup(); void pdw(); Splay(); } nil , *rt; Splay :: Splay(){fa = ch[0] = ch[1] = nil;} void Splay :: pup(){ siz = ch[0]->siz + ch[1]->siz + 1; sum = ch[0]->sum + ch[1]->sum + num; lmx = max(ch[0]->lmx, ch[0]->sum + num + ch[1]->lmx); lmn = min(ch[0]->lmn, ch[0]->sum + num + ch[1]->lmn); rmx = max(ch[1]->rmx, ch[1]->sum + num + ch[0]->rmx); rmn = min(ch[1]->rmn, ch[1]->sum + num + ch[0]->rmn); } void Splay :: pdw(){ if(_cov){ ch[0]->cov(_cov), ch[1]->cov(_cov); _cov = 0; } if(_flip){ ch[0]->flip(), ch[1]->flip(); _flip = 0; } if(_rev){ ch[0]->rev(), ch[1]->rev(); _rev = 0; } } void rotate(Splay *x, Splay *&k){ int d = x->d(); Splay *p = x->fa; p->sc(x->ch[!d], d); if(p == k){ x->fa = k->fa; k = x; } else p->fa->sc(x, p->d()); x->sc(p, !d); p->pup(); x->pup(); } void splay(Splay *x, Splay *&k){ for(Splay *y; x != k;){ if((y = x->fa) != k) y->fa->pdw(); y->pdw(); x->pdw(); if(y != k) (x->d() ^ y->d()) ? rotate(x, k) : rotate(y, k); rotate(x, k); } } Splay* select(int k){ Splay *p = rt; while(true){ p->pdw(); int t = p->ch[0]->siz; if(k <= t) p = p->ch[0]; else if(k > t + 1){ k -= t + 1; p = p->ch[1]; } else break; } return p; } void init(){ char s ; n = read(); m = read(); scanf("%s", s); nil[1].sum = 0, nil[1].siz = 1; rt = nil + 1; for(int i = 0; i < n; i++){ nil[2+i].siz = 1; nil[2+i].cov((s[i] == '(') ? 1 : -1); rt->sc(nil+(2+i), 1); splay(nil+(2+i), rt); } nil[2+n].sum = 0, nil[2+n].siz = 1; rt->sc(nil+(2+n), 1); splay(nil+(2+n), rt); } void work(){ char s ; Splay *u, *v; int x, y; while(m--){ scanf("%s", s); x = read(); y = read(); u = select(x); splay(u, rt); u = select(y+2); splay(u, rt->ch[1]); v = rt->ch[1]->ch[0]; switch(s[0]){ case 'R': scanf("%s", s); v->cov((s[0] == '(') ? 1 : -1); break; case 'S': v->rev(); break; case 'I': v->flip(); break; case 'Q': printf("%d\n", (abs(v->lmn)+1) / 2 + (abs(v->rmx)+1) / 2); break; } } } int main(){ init(); work(); return 0; }
相关文章推荐
- Bzoj2329: [HNOI2011]括号修复
- 【bzoj2329】[HNOI2011]括号修复 splay
- ●BZOJ 2329 [HNOI2011]括号修复.cpp
- BZOJ 2209: [Jsoi2011]括号序列&&BZOJ 2329: [HNOI2011]括号修复
- 【BZOJ2329/2209】[HNOI2011]括号修复/[Jsoi2011]括号序列 Splay
- [BZOJ2329][HNOI2011]括号修复-splay
- bzoj2329 [HNOI2011]括号修复
- bzoj2329 [HNOI2011]括号修复
- [BZOJ2329][HNOI2011]括号修复
- 2329: [HNOI2011]括号修复 - BZOJ
- BZOJ2329 [HNOI2011]括号修复
- bzoj2329 [HNOI2011]括号修复(splay)
- 【bzoj2329】[HNOI2011]括号修复 Splay
- BZOJ 2329: [HNOI2011]括号修复( splay )
- 【BZOJ】2329: [HNOI2011]括号修复(splay+特殊的技巧)
- BZOJ 2329 HNOI2011 括号修复 Splay
- BZOJ2329: [HNOI2011]括号修复
- bzoj千题计划222:bzoj2329: [HNOI2011]括号修复(fhq treap)
- BZOJ 2329 HNOI 2011 括号修复 —— 标记处理的原则
- BZOJ2329 HNOI2011 括号修复 splay+贪心