题目大意:
给定一串括号,现在有两种操作:
1. 翻转第x个括弧;
2. 对于区间[l, r]内,消去所有匹配的扩后后,查询消除后第k个括弧原来的位置是第几,若k大于消除后的区间长度,输出-1.
正统线段树t了,用了点黑魔法!
#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
#define MAXN 200100
inline int RD(int &x)
{
x = 0;
char ch = getchar();
while(!isdigit(ch)) { if(ch == '-') exit(0); ch = getchar(); if(ch == EOF) return 0; }
while(isdigit(ch)) { x *= 10; x += ch - '0'; ch = getchar(); }
return 1;
}
struct Node
{
int l, r, mate;
Node() {}
Node(int _l, int _r, int _m): l(_l), r(_r), mate(_m) {}
};
int M;
Node tree[MAXN << 2];
char str[MAXN];
void Init(int n)
{
n <<= 2;
for(int i = 1; i <= n; i++) tree[i] = Node(0, 0, 0);
}
void Pushup(int rt)
{
int t = min(tree[rt << 1].l, tree[rt << 1 | 1].r);
tree[rt].mate = tree[rt << 1].mate + tree[rt << 1 | 1].mate + t;
tree[rt].l = tree[rt << 1].l + tree[rt << 1 | 1].l - t;
tree[rt].r = tree[rt << 1].r + tree[rt << 1 | 1].r - t;
}
void Build(int n)
{
for(M = 1; M <= n + 1; M <<= 1) ;
for(int i = M + 1; i <= M + n; i++)
{
if(str[i - M] == '(') tree[i].l++;
if(str[i - M] == ')') tree[i].r++;
}
for(int i = M - 1; i; i--) Pushup(i);
}
void Update(int p)
{
p += M;
swap(tree[p].l, tree[p].r);
for(p >>= 1; p; p >>= 1) Pushup(p);
}
Node Query(int s, int t)
{
Node lch(0, 0, 0), rch(0, 0, 0);
int ltot, rtot, mtot, mt;
for(s += M - 1, t += M + 1; s ^ t ^ 1; s >>=1 , t >>= 1)
{
if(~s & 1)
{
mt = min(lch.l, tree[s ^ 1].r);
ltot = lch.l + tree[s ^ 1].l - mt;
rtot = lch.r + tree[s ^ 1].r - mt;
mtot = lch.mate + tree[s ^ 1].mate + mt;
lch = Node(ltot, rtot, mtot);
}
if(t & 1)
{
mt = min(rch.r, tree[t ^ 1].l);
ltot = rch.l + tree[t ^ 1].l - mt;
rtot = rch.r + tree[t ^ 1].r - mt;
mtot = rch.mate + tree[t ^ 1].mate + mt;
rch = Node(ltot, rtot, mtot);
}
}
mt = min(lch.l, rch.r);
ltot = lch.l + rch.l - mt;
rtot = lch.r + rch.r - mt;
mtot = lch.mate + rch.mate + mt;
return Node(ltot, rtot, mtot);
}
int find(int s, int e, int l, int r, int k)
{
int m, t, ck;
Node lch, rch;
while(l < r)
{
m = (l + r) >> 1;
lch = Query(s, m);
rch = Query(m + 1, e);
t = min(lch.l, rch.r);
ck = m - s + 1 - lch.mate * 2 - t;
if(ck >= k) r = m;
if(ck < k) l = m + 1;
}
return r;
}
int n, q, op, x, l, r, k, m;
int main()
{
// freopen("1004.in", "r", stdin);
int cas; scanf("%d", &cas);
while(cas--)
{
scanf("%d%d", &n, &q);
scanf("%s", str + 1);
Init(n);
Build(n);
while(q--)
{
scanf("%d", &op);
if(op == 1)
{
scanf("%d", &x);
Update(x);
}
else
{
RD(l), RD(r), RD(k);
int len = r - l + 1;
Node tot = Query(l, r);
if(k > len - tot.mate * 2) puts("-1");
else printf("%d\n", find(l, r, l, r, k));
}
}
}
return 0;
}