这道题的关键就是知道一个修复一个括号序列的最小改变数
把'('变成1,')'变成-1,lmi为左起最小连续子段和(可以为空),sum为序列的和,则答案为(lim+1)/2+(sum-lmi+1)/2
简单想了想,设i为lmi的结束下标,则有[1, i]所有的'('全部被匹配,[i+1, n]全部的‘)’都被匹配,如果不满足这个性质的话,则lmi还可以更小,这与假设相矛盾,所以-lmi就是[1,i]中没有被匹配的')'个数,而sum-lmi就是[i+1, n]没有被匹配的'('个数,所以只要分别修改[1,i]中的')'和[i+1]中的'('即可,由于原序列长度为偶数,所以|lmi|+|sum-lmi|一定是偶数,但
|lmi|和|sum-lmi|不一定是偶数,对于这种情况需要吧[1,i]中最后一个未匹配')'变为'(',[i+1,n]第一个未匹配'('变为')',而|lmi|-1和|sum-lmi|-1又变成了偶数,综合这两种情况就可以得到上面的式子
剩下的就是splay的各种鬼畜操作了
这种单纯考察数据结构的题我都要调试N多遍才能通过,看来代码能力还是需要加强额
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <utility> #include <ctime> using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::istringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; using std::deque; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; const int MAXN(50010); const int MAXM(10010); const int MAXE(10010); const int MAXH(19); const int INFI((INT_MAX-1) >> 1); const int MOD(10000); const ULL BASE(31); const LL LIM(10000000); const int INV(-10000); int arr[MAXN]; struct SPLAY_TREE { struct NODE { int num, size, flag1, flag2, flag3; //replace标记,reverse标记,inverse标记 int sum, lmi, rmi, lmx, rmx; //总和,左起连续最小和,右起连续最小和,左起连续最大和,右起连续最大和 NODE *fa; NODE *ch[2]; }; NODE pool[MAXN]; NODE *root, *NIL, *rear; inline void push_up(NODE *sour) //一定要注意NIL节点对push_up的影响 { sour->size = sour->ch[0]->size+sour->ch[1]->size+1; sour->sum = sour->ch[0]->sum+sour->ch[1]->sum+sour->num; sour->lmi = min(sour->ch[0]->lmi, sour->ch[0]->sum+sour->num+sour->ch[1]->lmi); sour->rmi = min(sour->ch[1]->rmi, sour->ch[1]->sum+sour->num+sour->ch[0]->rmi); sour->lmx = max(sour->ch[0]->lmx, sour->ch[0]->sum+sour->num+sour->ch[1]->lmx); sour->rmx = max(sour->ch[1]->rmx, sour->ch[1]->sum+sour->num+sour->ch[0]->rmx); } inline void updata_rep(NODE *sour, int v) { if(sour == NIL) return; sour->num = v; sour->sum = v*sour->size; sour->rmi = sour->lmi = v > 0? 0: v*sour->size; sour->lmx = sour->rmx = v > 0? v*sour->size: 0; sour->flag1 = v; sour->flag2 = 0; sour->flag3 = 0; } inline void updata_rev(NODE *sour) { if(sour == NIL) return; swap(sour->ch[0], sour->ch[1]); swap(sour->lmi, sour->rmi); swap(sour->lmx, sour->rmx); sour->flag2 ^= 1; } inline void updata_inv(NODE *sour) { if(sour == NIL) return; int temp = sour->lmi; swap(sour->lmi, sour->lmx); swap(sour->rmi, sour->rmx); sour->lmi *= -1; sour->lmx *= -1; sour->rmi *= -1; sour->rmx *= -1; sour->num *= -1; sour->sum *= -1; if(sour->flag1) sour->flag1 *= -1; else sour->flag3 ^= 1; } void push_down(NODE *sour) //和线段树的push_down一样,是对子节(注意不是本节点)进行更新 { if(sour->flag1) { updata_rep(sour->ch[0], sour->flag1); updata_rep(sour->ch[1], sour->flag1); sour->flag1 = 0; } if(sour->flag2) { updata_rev(sour->ch[0]); updata_rev(sour->ch[1]); sour->flag2 = 0; } if(sour->flag3) { updata_inv(sour->ch[0]); updata_inv(sour->ch[1]); sour->flag3 = 0; } } void initNIL() { NIL->ch[0] = NIL->ch[1] = NIL->fa = NIL; NIL->lmi = NIL->rmi = NIL->lmx = NIL->rmx = NIL->sum = NIL->num = 0; NIL->size = 0; } void init(int n) { NIL = pool; initNIL(); rear = pool+1; newnode(root, NIL, -100000); //插入无穷小 newnode(root->ch[1], root, 100000); //插入无穷大 build_tree(root->ch[1]->ch[0], root->ch[1], 1, n); //建树 push_up(root->ch[1]); push_up(root); } void newnode(NODE *&sour, NODE *f, int num) { sour = rear++; sour->num = sour->sum = num; sour->size = 1; sour->lmi = sour->rmi = num > 0? 0: num; sour->lmx = sour->rmx = num > 0? num: 0; sour->flag1 = sour->flag2 = sour->flag3 = 0; sour->fa = f; sour->ch[0] = sour->ch[1] = NIL; } void build_tree(NODE *&sour, NODE *f, int l, int r) { if(l > r) return; int m = (l+r) >> 1; newnode(sour, f, arr[m]); build_tree(sour->ch[0], sour, l, m-1); build_tree(sour->ch[1], sour, m+1, r); push_up(sour); } void rotate(NODE *sour, int flag) { NODE *f = sour->fa; push_down(f); push_down(sour); f->ch[!flag] = sour->ch[flag]; sour->ch[flag]->fa = f; sour->fa = f->fa; if(f->fa != NIL) f->fa->ch[f->fa->ch[1] == f] = sour; sour->ch[flag] = f; f->fa = sour; push_up(f); } void splay(NODE *sour, NODE *goal) { push_down(sour); while(sour->fa != goal) { if(sour->fa->fa == goal) rotate(sour, sour->fa->ch[0] == sour); else { NODE *f = sour->fa; int flag = (f->fa->ch[0] == f); if(f->ch[flag] == sour) rotate(sour, !flag); else rotate(f, flag); rotate(sour, flag); } } push_up(sour); if(goal == NIL) root = sour; } NODE *select(NODE *sour, int r) { while(sour != NIL) { push_down(sour); if(r == sour->ch[0]->size+1) break; if(r <= sour->ch[0]->size) sour = sour->ch[0]; else { r -= sour->ch[0]->size+1; sour = sour->ch[1]; } } return sour; } inline void pick(int pos1, int pos2) { NODE *tp = select(root, pos1); splay(tp, NIL); tp = select(root, pos2+2); splay(tp, root); } void REPLACE(int pos1, int pos2, int value) { pick(pos1, pos2); updata_rep(root->ch[1]->ch[0], value); push_up(root->ch[1]); push_up(root); } void SWAP(int pos1, int pos2) { pick(pos1, pos2); updata_rev(root->ch[1]->ch[0]); push_up(root->ch[1]); push_up(root); } void INVERT(int pos1, int pos2) { pick(pos1, pos2); updata_inv(root->ch[1]->ch[0]); push_up(root->ch[1]); push_up(root); } int QUERY(int pos1, int pos2) { pick(pos1, pos2); NODE *tp = root->ch[1]->ch[0]; return (abs(tp->sum-tp->lmi)+1)/2+(abs(tp->lmi)+1)/2; } }; SPLAY_TREE spt; char str[10]; int op1, op2; char op3; int main() { int TC, n_case(0); scanf("%d", &TC); while(TC--) { int n, m; scanf("%d%d", &n, &m); char temp; for(int i = 1; i <= n; ++i) { scanf(" %c", &temp); arr[i] = temp == '('? 1: -1; } spt.init(n); printf("Case %d:\n", ++n_case); for(int i = 0; i < m; ++i) { scanf("%s", str); if(str[0] == 'R') { scanf("%d%d %c", &op1, &op2, &op3); spt.REPLACE(op1, op2, op3 == '('? 1: -1); } else if(str[0] == 'S') { scanf("%d%d", &op1, &op2); spt.SWAP(op1, op2); } else if(str[0] == 'I') { scanf("%d%d", &op1, &op2); spt.INVERT(op1, op2); } else { scanf("%d%d", &op1, &op2); printf("%d\n", spt.QUERY(op1, op2)); } } } return 0; }
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <utility> #include <ctime> using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::istringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; using std::deque; typedef long long LL; typedef unsigned long long ULL; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; const int MAXN(50010); const int MAXM(10010); const int MAXE(10010); const int MAXH(19); const int INFI((INT_MAX-1) >> 1); const int MOD(10000); const ULL BASE(31); const LL LIM(10000000); const int INV(-10000); int arr[MAXN]; struct SPLAY_TREE { struct NODE { int num, size, flag1, flag2, flag3; int sum, lmi, rmi; //区域和 ,左起连续最小和(可以0个元素), 右起连续最小和(可以0个元素) NODE *fa; NODE *ch[2]; }; NODE pool[MAXN]; NODE *root, *NIL, *rear; inline void push_up(NODE *sour) //一定要注意NIL节点对push_up的影响 { sour->size = sour->ch[0]->size+sour->ch[1]->size+1; sour->sum = sour->ch[0]->sum+sour->ch[1]->sum+sour->num; sour->lmi = min(sour->ch[0]->lmi, sour->ch[0]->sum+sour->num+sour->ch[1]->lmi); sour->rmi = min(sour->ch[1]->rmi, sour->ch[1]->sum+sour->num+sour->ch[0]->rmi); } inline void updata_rep(NODE *sour, int v) { if(sour == NIL) return; sour->num = v; sour->sum = v*sour->size; sour->rmi = sour->lmi = v > 0? 0: v*sour->size; sour->flag1 = v; sour->flag2 = 0; sour->flag3 = 0; } inline void updata_rev(NODE *sour) { if(sour == NIL) return; swap(sour->ch[0], sour->ch[1]); swap(sour->lmi, sour->rmi); sour->flag2 ^= 1; } inline void updata_inv(NODE *sour) { if(sour == NIL) return; int temp = sour->lmi; sour->lmi = -(sour->sum-sour->rmi); sour->rmi = -(sour->sum-temp); sour->sum *= -1; sour->num *= -1; if(sour->flag1) sour->flag1 *= -1; else sour->flag3 ^= 1; } void push_down(NODE *sour) //和线段树的push_down一样,是对子节(注意不是本节点)进行更新 { if(sour->flag1) { updata_rep(sour->ch[0], sour->flag1); updata_rep(sour->ch[1], sour->flag1); sour->flag1 = 0; } if(sour->flag2) { updata_rev(sour->ch[0]); updata_rev(sour->ch[1]); sour->flag2 = 0; } if(sour->flag3) { updata_inv(sour->ch[0]); updata_inv(sour->ch[1]); sour->flag3 = 0; } } void initNIL() { NIL->ch[0] = NIL->ch[1] = NIL->fa = NIL; NIL->lmi = NIL->rmi = NIL->sum = NIL->num = 0; NIL->size = 0; } void init(int n) { NIL = pool; initNIL(); rear = pool+1; newnode(root, NIL, -100000); //插入无穷小 newnode(root->ch[1], root, 100000); //插入无穷大 build_tree(root->ch[1]->ch[0], root->ch[1], 1, n); //建树 push_up(root->ch[1]); push_up(root); } void newnode(NODE *&sour, NODE *f, int num) { sour = rear++; sour->num = sour->sum = num; sour->size = 1; sour->lmi = sour->rmi = num > 0? 0: num; sour->flag1 = sour->flag2 = sour->flag3 = 0; sour->fa = f; sour->ch[0] = sour->ch[1] = NIL; } void build_tree(NODE *&sour, NODE *f, int l, int r) { if(l > r) return; int m = (l+r) >> 1; newnode(sour, f, arr[m]); build_tree(sour->ch[0], sour, l, m-1); build_tree(sour->ch[1], sour, m+1, r); push_up(sour); } void rotate(NODE *sour, int flag) { NODE *f = sour->fa; push_down(f); push_down(sour); f->ch[!flag] = sour->ch[flag]; sour->ch[flag]->fa = f; sour->fa = f->fa; if(f->fa != NIL) f->fa->ch[f->fa->ch[1] == f] = sour; sour->ch[flag] = f; f->fa = sour; push_up(f); } void splay(NODE *sour, NODE *goal) { push_down(sour); while(sour->fa != goal) { if(sour->fa->fa == goal) rotate(sour, sour->fa->ch[0] == sour); else { NODE *f = sour->fa; int flag = (f->fa->ch[0] == f); if(f->ch[flag] == sour) rotate(sour, !flag); else rotate(f, flag); rotate(sour, flag); } } push_up(sour); if(goal == NIL) root = sour; } NODE *select(NODE *sour, int r) { while(sour != NIL) { push_down(sour); if(r == sour->ch[0]->size+1) break; if(r <= sour->ch[0]->size) sour = sour->ch[0]; else { r -= sour->ch[0]->size+1; sour = sour->ch[1]; } } return sour; } inline void pick(int pos1, int pos2) { NODE *tp = select(root, pos1); splay(tp, NIL); tp = select(root, pos2+2); splay(tp, root); } void REPLACE(int pos1, int pos2, int value) { pick(pos1, pos2); updata_rep(root->ch[1]->ch[0], value); push_up(root->ch[1]); push_up(root); } void SWAP(int pos1, int pos2) { pick(pos1, pos2); updata_rev(root->ch[1]->ch[0]); push_up(root->ch[1]); push_up(root); } void INVERT(int pos1, int pos2) { pick(pos1, pos2); updata_inv(root->ch[1]->ch[0]); push_up(root->ch[1]); push_up(root); } int QUERY(int pos1, int pos2) { pick(pos1, pos2); NODE *tp = root->ch[1]->ch[0]; return (abs(tp->sum-tp->lmi)+1)/2+(abs(tp->lmi)+1)/2; } }; SPLAY_TREE spt; char str[10]; int op1, op2; char op3; int main() { int TC, n_case(0); scanf("%d", &TC); while(TC--) { int n, m; scanf("%d%d", &n, &m); char temp; for(int i = 1; i <= n; ++i) { scanf(" %c", &temp); arr[i] = temp == '('? 1: -1; } spt.init(n); printf("Case %d:\n", ++n_case); for(int i = 0; i < m; ++i) { scanf("%s", str); if(str[0] == 'R') { scanf("%d%d %c", &op1, &op2, &op3); spt.REPLACE(op1, op2, op3 == '('? 1: -1); } else if(str[0] == 'S') { scanf("%d%d", &op1, &op2); spt.SWAP(op1, op2); } else if(str[0] == 'I') { scanf("%d%d", &op1, &op2); spt.INVERT(op1, op2); } else { scanf("%d%d", &op1, &op2); printf("%d\n", spt.QUERY(op1, op2)); } } } return 0; }