Gym 100803G 线段树
2015-12-02 21:59
483 查看
好长时间前做的题,来补一下题解。
给出括号化的序列,每次改变一个括号方向,求出下标p,是的改变p处的括号方向可以使括号化仍然成立,且p最小。
保证括号化看似和线段树没有联系,我们可以把括号"("表示为1,把括号")"表示为-1,则保证括号化的充要条件就是使数字序列前缀和始终大于等于零
用线段树维护前缀和
查询有两种情况
1. "(" 变成 ")"
这种情况我们只需找到最左边的一个")",就是答案。(可以用一个set维护所有的")"的位置)
2.")" 变成 "("
这种情况我们要找一个最左边的“(”变成”)“,也就是把p处及以后的前缀和都减2,且不能出现负的前缀和。
于是我们就要借助线段树查询前缀和小于2的最右边节点,这样把区间[p + 1, n]减二之后才不会出现负值。
用线段树维护区间最小值,也就是区间最小前缀和。线段树能往右走就往又走,注意查询过程中区间边界的特判处理。
给出括号化的序列,每次改变一个括号方向,求出下标p,是的改变p处的括号方向可以使括号化仍然成立,且p最小。
保证括号化看似和线段树没有联系,我们可以把括号"("表示为1,把括号")"表示为-1,则保证括号化的充要条件就是使数字序列前缀和始终大于等于零
用线段树维护前缀和
查询有两种情况
1. "(" 变成 ")"
这种情况我们只需找到最左边的一个")",就是答案。(可以用一个set维护所有的")"的位置)
2.")" 变成 "("
这种情况我们要找一个最左边的“(”变成”)“,也就是把p处及以后的前缀和都减2,且不能出现负的前缀和。
于是我们就要借助线段树查询前缀和小于2的最右边节点,这样把区间[p + 1, n]减二之后才不会出现负值。
用线段树维护区间最小值,也就是区间最小前缀和。线段树能往右走就往又走,注意查询过程中区间边界的特判处理。
#include<cstdio> #include<algorithm> #include<cstring> #include<set> #include<iostream> #define lson o << 1, L, M #define rson (o << 1) | 1, M + 1, R using namespace std; const int MAXN = 300010; const int INF = 0x3f3f3f3f; char str[MAXN]; int num[MAXN]; int minv[MAXN << 2]; int addv[MAXN << 2]; int len; void pushup(int o, int L, int R) { minv[o] = 0; if(R > L) { minv[o] = min(minv[o << 1], minv[(o << 1) | 1]); } minv[o] += addv[o]; } void update(int p, int v, int o, int L, int R) { if(p == L && p == R) { addv[o] = v; minv[o] = 0; } else { int M = L + (R - L) / 2; if(p <= M) update(p, v, lson); else update(p, v, rson); }pushup(o, L, R); } void add(int l, int r, int v, int o, int L, int R) { if(l <= L && r >= R) { addv[o] += v; } else { int M = L + (R - L) / 2; if(l <= M)add(l, r, v, lson); if(r > M) add(l, r, v, rson); } pushup(o, L, R); } int query_min(int l ,int r, int add, int o, int L, int R) { if(l <= L && r >= R) { return minv[o] + add; } else { int M = L + (R - L) / 2; int res = INF; if(l <= M) res = min(res, query_min(l, r, add + addv[o],lson)); if(r > M) res = min(res, query_min(l, r, add + addv[o], rson)); return res; } } int query(int l, int r, int add, int o, int L, int R) { //cout << L << "!!!" << R << endl; if(L == R) { if(L == 1) { if(minv[o] + add >= 2) return 0; return L; } else { return L; } } int M = L + (R - L) / 2; if(r < M + 1) return query(l, r, add + addv[o], lson); int minr = query_min(M + 1, min(r, R), 0, 1, 1, len); if(minr < 2) return query(l, r, add + addv[o], rson); return query(l, r, add + addv[o], lson); } int main() { int n, q; set<int> fir; scanf("%d%d", &n, &q); scanf("%s", str + 1); len = n; for(int i = 1 ; i <= len ; i++) if(str[i] == '(') num[i] = 1; else { num[i] = -1; fir.insert(i); } for(int i = 1 ; i <= len ; i++) num[i] += num[i - 1]; for(int i = 1 ; i <= len ; i++) update(i, num[i], 1, 1, len); //cout << query_min(1, 1, 0, 1, 1, len) << "!!" << endl; for(int i = 0 ; i < q ; i++) { //cout << str + 1 << endl; int pos; scanf("%d", &pos); if(str[pos] == '(') { str[pos] = ')'; fir.insert(pos); int pp = *fir.begin(); fir.erase(fir.begin()); add(pos, len, -2, 1, 1, len); add(pp, len, 2, 1, 1, len); printf("%d\n", pp); str[pp] = '('; } else { // str[pos] == ')' str[pos] = '('; add(pos, len, 2, 1, 1, len); fir.erase(pos); int pp = query(1, pos, 0, 1, 1, len); //cout << pp << "~~" << endl; pp++; str[pp] = ')'; fir.insert(pp); add(pp, len, -2, 1, 1, len); printf("%d\n", pp); } } return 0; }
相关文章推荐
- 1050. String Subtraction (20)
- Xcode安装VVDocumenter文档注释插件
- error: stray ‘\240’ in program或 error: stray ‘\302’ in program
- 正则表达式
- 拥抱高效、拥抱 Bugtags 之来自用户的声音 1
- http协议(接触ajax时学习)
- runtime是什么以及怎么用
- Bootstrap3 - Using glyphicon as background image in CSS
- java 正则表达式浅析
- Codeforces Round #334(div.2)(新增不用二分代码) B
- C语言纪要
- 【IOS网络】ATS的小总结
- MySQL中的find_in_set(A, B)函数,判断字符串A是否存在B中
- 蓝海、红海指的是什么
- Handlerbars基础笔记
- 技能UP:SAP OBYC自动记账的实例说明(含value String应用说明)
- 【Codeforces Round 334 (Div 2)D】【数论 置换群 典型数据特判 附带打表代码】Moodular Arithmetic 满足f(k x)=k f(x)的映射个数
- Kuryr项目简介
- 1030. Travel Plan (30)【最短路+路径记忆】——PAT (Advanced Level) Practise
- 【黑马程序员】第五章:多线程