bzoj2329 [HNOI2011]括号修复
2329: [HNOI2011]括号修复
Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 1232 Solved: 581
[Submit][Status][Discuss]
分析:第一次做觉得这道题好神啊!思维量和代码量都惊人!今天早上又花20min码了一次,觉得这只不过是一个套路题罢了.
这道题实际上是由两个子问题组合而成,首先要知道怎么求将一个括号序列变成合法的括号序列需要的操作次数,还要知道怎么维护.第二问比较容易看出来,因为涉及到区间翻转操作嘛,那就用splay维护.第一问是一个经典问题,如果将匹配的()括号拿走,剩下的括号就变成了形如:))))))((((((((.答案就是左边括号的数量 / 2上取整 + 右边括号的数量 / 2上取整.
那么怎么把这两个东西结合在一起呢?也就是说,怎么维护左边的))))括号数量和右边的(((((括号数量呢?我一开始的想法是维护()的数量,用总的(,)数量-()的数量.实际上会有((()))这种嵌套的括号,比较难以维护.
于是套路来了.将(看作-1,)看作1,求一下左边最小连续和与右边最大连续和就是)(括号的数量了.答案向上面说的那样统计就好了.
关键是有3个操作,每个操作都会打上标记,标记有点不好处理.处理标记要看标记与标记之间的影响,标记下放的顺序以及标记对区间信息的影响.
如果有replace标记,那么肯定是它先下放,然后replace标记就会清空,它会清空掉swap和invert标记,并改变当前区间的sum和值v.
swap标记对其他标记没影响,只是让lmax,rmax;lmin,rmin交换一下,并且交换左右子树.
invert标记是将lmax,rmax,lmin,rmin分别取反后,lmax与lmin交换,rmax与rmin交换.同时让v和sum取反.对其它标记没有影响.
注意点:splay和线段树不同,splay上的每个节点不只代表一个区间,还会代表一个值.在pushup和下放标记的时候要考虑对这个值的影响.
#include <cstdio> #include <cmath> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 200010; int n,m,root,tot,rev[maxn],w[maxn],inverttag[maxn],replacetag[maxn],swaptag[maxn]; char s[maxn]; struct node { int sum,lmax,rmax,lmin,rmin,sizee,left,right,v,fa,id; } e[maxn]; void swap(int x) { swap(e[x].lmax,e[x].rmax); swap(e[x].lmin,e[x].rmin); swap(e[x].left,e[x].right); swaptag[x] ^= 1; } void replace(int x,int d) { e[x].v = d; e[x].sum = d * e[x].sizee; e[x].lmax = e[x].rmax = max(e[x].sum,0); e[x].lmin = e[x].rmin = min(e[x].sum,0); swaptag[x] = inverttag[x] = 0; replacetag[x] = d; } void invert(int x) { e[x].lmin = -e[x].lmin; e[x].lmax = -e[x].lmax; e[x].rmin = -e[x].rmin; e[x].rmax = -e[x].rmax; swap(e[x].lmin,e[x].lmax); swap(e[x].rmin,e[x].rmax); e[x].sum = -e[x].sum; e[x].v = -e[x].v; inverttag[x] ^= 1; } void pushdown(int x) { if (replacetag[x] != 0) { if (e[x].left) replace(e[x].left,replacetag[x]); if (e[x].right) replace(e[x].right,replacetag[x]); replacetag[x] = 0; } if (inverttag[x] != 0) { if (e[x].left) invert(e[x].left); if (e[x].right) invert(e[x].right); inverttag[x] = 0; } if (swaptag[x] != 0) { if (e[x].left) swap(e[x].left); if (e[x].right); swap(e[x].right); swaptag[x] = 0; } } void pushup(int x) { e[x].sizee = 1 + e[e[x].left].sizee + e[e[x].right].sizee; e[x].sum = e[x].v + e[e[x].left].sum + e[e[x].right].sum; e[x].lmax = max(e[e[x].left].lmax,e[e[x].left].sum + e[x].v + e[e[x].right].lmax); e[x].rmax = max(e[e[x].right].rmax,e[e[x].right].sum + e[x].v + e[e[x].left].rmax); e[x].lmin = min(e[e[x].left].lmin,e[e[x].left].sum + e[x].v + e[e[x].right].lmin); e[x].rmin = min(e[e[x].right].rmin,e[e[x].right].sum + e[x].v + e[e[x].left].rmin); } void build(int l,int r,int &x,int y) { if (l > r) return; int mid = (l + r) >> 1; x = ++tot; e[x].v = w[mid]; e[x].fa = y; if (l == r) { e[x].sizee = 1; e[x].sum = e[x].v; e[x].lmin = e[x].rmin = min(0,e[x].sum); e[x].lmax = e[x].rmax = max(0,e[x].sum); return; } build(l,mid - 1,e[x].left,x); build(mid + 1,r,e[x].right,x); pushup(x); } void turnr(int x) { pushdown(x); int y = e[x].fa; int z = e[y].fa; e[y].left = e[x].right; if (e[x].right != 0) e[e[x].right].fa = y; e[x].fa = z; if (z != 0) { if (e[z].left == y) e[z].left = x; else e[z].right = x; } e[x].right = y; e[y].fa = x; pushup(y); pushup(x); } void turnl(int x) { pushdown(x); int y = e[x].fa; int z = e[y].fa; e[y].right = e[x].left; if (e[x].left != 0) e[e[x].left].fa = y; e[x].fa = z; if (z != 0) { if (e[z].left == y) e[z].left = x; else e[z].right = x; } e[x].left = y; e[y].fa = x; pushup(y); pushup(x); } void splay(int x,int yy) { while (e[x].fa != yy) { pushdown(x); int y = e[x].fa; int z = e[y].fa; if (z == 0 || z == yy) { if (e[y].left == x) turnr(x); else turnl(x); } else { if (e[z].left == y && e[y].left == x) { turnr(y); turnr(x); } else { if (e[z].right == y && e[y].right == x) { turnl(y); turnl(x); } else { if (e[z].left == y && e[y].right == x) { turnl(x); turnr(x); } else { turnr(x); turnl(x); } } } } } if (yy == 0) root = x; pushup(x); } int find(int k,int x) { pushdown(x); if (k > e[e[x].left].sizee + 1) return find(k - 1 - e[e[x].left].sizee,e[x].right); if (k == e[e[x].left].sizee + 1) return x; return find(k,e[x].left); } void Replace(int x,int y,int d) { int pos1 = find(x,root),pos2 = find(y + 2,root); splay(pos1,0); splay(pos2,pos1); int pos = e[pos2].left; replace(pos,d); } void Swap(int x,int y) { int pos1 = find(x,root),pos2 = find(y + 2,root); splay(pos1,0); splay(pos2,pos1); int pos = e[pos2].left; swap(pos); } void Invert(int x,int y) { int pos1 = find(x,root),pos2 = find(y + 2,root); splay(pos1,0); splay(pos2,pos1); int pos = e[pos2].left; invert(pos); } int query(int x,int y) { int pos1 = find(x,root),pos2 = find(y + 2,root); splay(pos1,0); splay(pos2,pos1); int pos = e[pos2].left; return (e[pos].lmax + 1) / 2 + (abs(e[pos].rmin) + 1) / 2; } int main() { scanf("%d%d",&n,&m); scanf("%s",s + 1); for (int i = 1; i <= n; i++) { if (s[i] == '(') w[i] = -1; else w[i] = 1; } build(0,n + 1,root,0); while (m--) { char ch[10]; scanf("%s",ch); int x,y; scanf("%d%d",&x,&y); if (ch[0] == 'R') { scanf("%s",ch); int temp = 0; if (ch[0] == '(') temp = -1; if (ch[0] == ')') temp = 1; Replace(x,y,temp); } if (ch[0] == 'Q') printf("%d\n",query(x,y)); if (ch[0] == 'S') Swap(x,y); if (ch[0] == 'I') Invert(x,y); } return 0; }