UESTC_1546

    这个题目可以借用判断合法括号序列的办法,将’(’看作1,将’)’看作-1,之后从左向右扫描一个序列并将扫描到的值累加起来,在这个过程中如果任意时刻这些值的和都不小于0,并且最后的时候这些值的和为0,那么就说明这个括号序列是合法的。

    于是我们只要再用线段树实现修改及查询的操作,这个题目就算是解决了。为了便于修改和查询,我们可以用两个标记to、rev,to表示这个区间是否被set,rev表示这个区间是否被翻转。同时我们可以维护3个值lmin、lmax、sum,lmin表示从当前区间左端点开始最小的前缀和,lmax表示从当前区间开始最大的前缀和,sum表示当前区间的和。

#include<stdio.h>
#include<string.h>
#define MAXD 100010
int N, M, to[4 * MAXD], rev[4 * MAXD], lmin[4 * MAXD], lmax[4 * MAXD], sum[4 * MAXD];
char b[MAXD];
void Swap(int &x, int &y)
{
    int t;
    t = x, x = -y, y = -t;
}
void pushdown(int cur, int x, int y)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;
    if(to[cur] != -1)
    {
        to[ls] = to[rs] = to[cur];
        rev[ls] = rev[rs] = 0;
        if(to[cur])
        {
            sum[ls] = mid - x + 1, sum[rs] = y - mid;
            lmin[ls] = lmin[rs] = 0;
            lmax[ls] = mid - x + 1, lmax[rs] = y - mid;
        }
        else
        {
            sum[ls] = -(mid - x + 1), sum[rs] = -(y - mid);
            lmin[ls] = -(mid - x + 1), lmin[rs] = -(y - mid);
            lmax[ls] = lmax[rs] = 0;
        }
        to[cur] = -1;
    }
    if(rev[cur])
    {
        rev[ls] ^= 1, rev[rs] ^= 1;
        sum[ls] = -sum[ls], sum[rs] = -sum[rs];
        Swap(lmin[ls], lmax[ls]), Swap(lmin[rs], lmax[rs]);
        rev[cur] = 0;
    }
}
void update(int cur)
{
    int ls = cur << 1, rs = cur << 1 | 1;
    sum[cur] = sum[ls] + sum[rs];
    lmin[cur] = lmin[ls];
    if(sum[ls] + lmin[rs] < lmin[cur])
        lmin[cur] = sum[ls] + lmin[rs];
    lmax[cur] = lmax[ls];
    if(sum[ls] + lmax[rs] > lmax[cur])
        lmax[cur] = sum[ls] + lmax[rs];
}
void build(int cur, int x, int y)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;
    to[cur] = -1, rev[cur] = 0;
    if(x == y)
    {
        if(b[x] == '(')
            sum[cur] = lmax[cur] = 1, lmin[cur] = 0;
        else
            sum[cur] = lmin[cur] = -1, lmax[cur] = 0;
        return ;
    }
    build(ls, x, mid);
    build(rs, mid + 1, y);
    update(cur);
}
void query(int cur, int x, int y, int s, int t, int &min, int &ss)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;
    if(x >= s && y <= t)
    {
        if(ss + lmin[cur] < min)
            min = ss + lmin[cur];
        ss += sum[cur];
        return ;
    }
    pushdown(cur, x, y);
    if(mid >= s)
        query(ls, x, mid, s, t, min, ss);
    if(mid + 1 <= t)
        query(rs, mid + 1, y, s, t, min, ss);
}
void refresh(int cur, int x, int y, int s, int t, int c)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;
    if(x >= s && y <= t)
    {
        to[cur] = c, rev[cur] = 0;
        if(c)
            sum[cur] = lmax[cur] = y - x + 1, lmin[cur] = 0;
        else
            sum[cur] = lmin[cur] = -(y - x + 1), lmax[cur] = 0;
        return ;
    }
    pushdown(cur, x, y);
    if(mid >= s)
        refresh(ls, x, mid, s, t, c);
    if(mid + 1 <= t)
        refresh(rs, mid + 1, y, s, t, c);
    update(cur);
}
void Reverse(int cur, int x, int y, int s, int t)
{
    int mid = (x + y) >> 1, ls = cur << 1, rs = cur << 1 | 1;
    if(x >= s && y <= t)
    {
        rev[cur] ^= 1;
        sum[cur] = -sum[cur], Swap(lmin[cur], lmax[cur]);
        return ;
    }
    pushdown(cur, x, y);
    if(mid >= s)
        Reverse(ls, x, mid, s, t);
    if(mid + 1 <= t)
        Reverse(rs, mid + 1, y, s, t);
    update(cur);
}
void solve()
{
    int i, q, x, y, min, ss;
    char ch[10];
    scanf("%d", &q);
    for(i = 0; i < q; i ++)
    {
        scanf("%s%d%d", ch, &x, &y);
        if(ch[0] == 's')
        {
            scanf("%s", ch);
            refresh(1, 0, N - 1, x, y, ch[0] == '(' ? 1 : 0);
        }
        else if(ch[0] == 'r')
            Reverse(1, 0, N - 1, x, y);
        else
        {
            min = ss = 0;
            query(1, 0, N - 1, x, y, min, ss);
            if(ss == 0 && min == 0)
                printf("YES\n");
            else
                printf("NO\n");
        }
    }
}
void init()
{
    scanf("%d", &N);
    scanf("%s", b);
    build(1, 0, N - 1);
}
int main()
{
    int t, tt;
    scanf("%d", &t);
    for(tt = 0; tt < t; tt ++)
    {
        init();
        printf("Case %d:\n", tt + 1);
        solve();
        printf("\n");
    }
    return 0;
}
posted on 2012-05-10 12:39  Staginner  阅读(295)  评论(0编辑  收藏  举报