您的位置:首页 > 其它

Gym 100803G 线段树

2015-12-02 21:59 483 查看
好长时间前做的题,来补一下题解。

给出括号化的序列,每次改变一个括号方向,求出下标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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: