Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others)
Submit 
Status

There is a sequence of brackets, which supports two kinds of operations.

  1. we can choose a interval [l,r][l,r],
    and set all the elements range in this interval to left bracket or right bracket.
  2. we can reverse a interval, which means that for all the elements range in [l,r][l,r],
    if it's left bracket at that time, we change it into right bracket, vice versa.

Fish is fond of Regular Bracket
Sequence
, so he want to know whether a interval [l,r][l,r] of
the sequence is regular or not after doing some operations.

Let us define a regular brackets sequence in the following way:

  1. Empty sequence is a regular sequence.
  2. If S is a regular sequence, then (S) is
    also a regular sequences.
  3. If A and B are
    regular sequences, then AB is a regular sequence.

Input

In the first line there is an integer TT (T≤10T≤10),
indicates the number of test cases. Each case begins with a line containing an integers NN (N≤100,000N≤100,000 and NN is
a even number), the size of the initial brackets sequence. The next line contains a string whose length is NN consisting
of ( and ).
In the third of each test case, there is an integer MM(M≤100,000M≤100,000)
indicates the number of queries. Each of the following MM lines
contains one operation as mentioned below. The index of the bracket sequence is labeled from 00to N−1N−1.

Three operation description:

  • set l r c: change all the elements range in [l,r][l,r] into ( or ).(cc is ( or ))
  • reverse l r: reverse the interval [l,r][l,r]
  • query l,r: you should answer that interval [l,r][l,r] is
    regular or not

Output

For each test case, print a line containing the test case number (beginning with 11)
on its own line, then the answer for each query operation, if the interval
is regular, print YES, otherwise print NO,
one on each line.

Print a blank line after each test case.

Sample input and output

Sample Input Sample Output
1
6
((()))
8
query 0 5
set 0 5 (
query 0 5
reverse 3 5
query 0 5
query 1 4
query 2 3
query 0 4
Case 1:
YES
NO
YES
YES
YES
NO

Hint

Huge input, use scanf instead
of cin.

Source

Classic Problem

【题解】

给你一段括号序列。

1.set操作 把[l,r]区间内的所有括号都置为相同的括号;

2.reverse操作 把[l,r]区间内的所有括号都置为相反。

3.询问操作。询问[l,r]这个区间的括号是否匹配了。

要用到栈的思想。

左括号是加1,右括号是减1.

累加器一开始为0;

当我们从左往右判断括号是否匹配的时候,就按照这个规则给累加器累加值。如果中间某个时刻累加的值小于0了。那就说明不匹配。因为右括号在某个时刻比前面的所有左括号的数目都多。这个时候就算最后的累加器值为0也没用。

用线段树来做。(一开始就把括号序列按照括号和数字对应的规则改成1,-1序列)

我们要记录某段区间内的累加值sum,还要记录这段区间从左往右一直按顺序逐个累加出现的最小值minlx。

当输入的询问l,r。满足sum[l..r]==0,且minlx[l..r]>=0,则这段是匹配的。

如果是单纯的整个区间的替换操作。sum值是比较好维护的。就是区间长度乘替换值。

从左到右按顺序累加值的最小值也可以根据替换的值的正负得出。是正就取1个,是反就取区间长度的个数。

但是如果要进行取反操作该怎么办呢??

可以动手实验一下。

设未取反之前,从左到右按顺序累加出现过的最大值和最小值为max,min

取反过后的则是max',min'

则满足max'=-min,min'=-max;

可以这样想。

max->a0+a1+a2+a3..+ax;

min'->-a0-a1-a2-a3..-ax;

因为max是从左往右加最大的。

那么取一个相反数。那么就变成从左往右加最小的了。

如果再加上一个a(x+1);

那么max值不会比原来大。

那么相应的-max也就不会比原来小了;

少掉最后一个元素ax也是同理,max值不会比原来大,对应-max也就不会比原来小了。

综上直接取-max就好了。

max'从min推出的原理也可以这样用类似方法想。

然后你只要知道set操作是可以覆盖取反操作就可以了。即不论你之前怎样取反。我都直接给你浇一桶冷水全部变成某个值。

在push_up的时候,你要明确,maxlx,minlx这两个值都是从区间的最左端不断往右加到一个合适的位置得到的。

这点在最后输出询问的时候也用到了。

每个测试点后面要多输出一个空行。你看到了吗?

另外我的代码在输入数据的时候把区间左右端点都加了1。这样整个区间就是[1..n]了。

【代码】

#include <cstdio>
#include <algorithm>
#define lson begin,m,rt<<1
#define rson m+1,end,rt<<1|1 using namespace std; const int MAXN = 100101; int n,m,a[MAXN],maxlx[MAXN*4],minlx[MAXN*4],sum[MAXN*4];
int af[MAXN * 4], as[MAXN * 4];
char s[MAXN]; void push_up(int rt)//想理解max和min的更新需要明确这两个值是从左往右一直累加到一个合适位置获得的
{
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
maxlx[rt] = max(maxlx[rt << 1], sum[rt << 1] + maxlx[rt << 1 | 1]);
minlx[rt] = min(minlx[rt << 1], sum[rt << 1] + minlx[rt << 1 | 1]);
} void build(int begin, int end, int rt)//建树。
{
as[rt] = 0;
af[rt] = 0;
maxlx[rt] = minlx[rt] = sum[rt] = 0;
if (begin == end)
{
maxlx[rt] = minlx[rt] = sum[rt] = a[begin];
return;
}
int m = (begin + end) >> 1;
build(lson);
build(rson);
push_up(rt);
} void input_data()
{
scanf("%d", &n);
scanf("%s", s);
for (int i = 1; i <= n; i++)
if (s[i-1] == '(')
a[i] = 1;
else
a[i] = -1;
build(1, n, 1);
scanf("%d", &m);
} void qufan(int &t)
{
if (t == 1)
t = -1;
else
t = 1;
} void tihuan(int rt,int len,int num)
{
sum[rt] = len*num;
if (num == 1)
{
maxlx[rt] = len;
minlx[rt] = 1;
}
else
{
maxlx[rt] = -1;
minlx[rt] = -len;
}
} void push_down(int rt,int len)
{
if (as[rt] != 0) //需要替换
{
as[rt << 1] = as[rt << 1 | 1] = as[rt];
af[rt << 1] = af[rt << 1 | 1] = 0; sum[rt << 1] = (len - (len >> 1))*as[rt];
tihuan(rt << 1, (len - (len >> 1)), as[rt]); sum[rt << 1 | 1] = (len >> 1)*as[rt];
tihuan(rt << 1 | 1, len >> 1, as[rt]); as[rt] = 0;
}
else //如果存在替换操作就不可能存在取反操作(可以想想为什么);
if (af[rt] != 0)
{
if (as[rt << 1] != 0)
{
qufan(as[rt << 1]);
tihuan(rt<<1, (len-(len>>1)), as[rt<<1]);
}
else
{
af[rt<<1] = 1 - af[rt<<1];
sum[rt<<1] = -sum[rt<<1];
int temp = maxlx[rt<<1];
maxlx[rt<<1] = -minlx[rt<<1];
minlx[rt<<1] = -temp;
} if (as[rt << 1|1] != 0)
{
qufan(as[rt << 1|1]);
tihuan(rt << 1|1,len >> 1, as[rt << 1|1]);
}
else
{
af[rt << 1|1] = 1 - af[rt << 1|1];
sum[rt << 1|1] = -sum[rt << 1|1];
int temp = maxlx[rt << 1|1];
maxlx[rt << 1|1] = -minlx[rt << 1|1];
minlx[rt << 1|1] = -temp;
}
af[rt] = 0;
}
} void up_data(int op, int l, int r, int num, int begin, int end, int rt)
{
if (l <= begin && end <= r)
{
if (op == 1) //all the same
{
tihuan(rt, end - begin + 1, num);
as[rt] = num;
af[rt] = 0;
}
else
if (op == 2) //all "fan"(pinyin)
{
if (as[rt] != 0)//如果之前有替换操作 就把替换的值取反就可以了
{
qufan(as[rt]);
tihuan(rt, end - begin + 1, as[rt]);
}
else
{
af[rt] = 1 - af[rt];
sum[rt] = -sum[rt];
int temp = maxlx[rt];
maxlx[rt] = -minlx[rt];
minlx[rt] = -temp;
}
}
return;
}
push_down(rt,end-begin+1);
int m = (begin + end) >> 1;
if (l <= m)
up_data(op, l, r, num, lson);
if (m < r)
up_data(op, l, r, num, rson);
push_up(rt);
} int query_sum(int l, int r, int begin, int end, int rt)//求l..r的区间和。
{
if (l <= begin && end <= r)
return sum[rt];
push_down(rt,end-begin+1);
int m = (begin + end) >> 1;
int dd = 0;
if (l <= m)
dd += query_sum(l, r, lson);
if (m < r)
dd += query_sum(l, r, rson);
return dd;
} int query_min(int l, int r, int begin, int end, int rt) //求得l..r这个区间从最左往右加出现过的最小值。
{
if (l == begin && r == end)
return minlx[rt];
push_down(rt, end - begin + 1);
int m = (begin + end) >> 1;
if (r <= m)//所求区间在这个端点所代表的区间的左边。
return query_min(l, r, lson);
else
if (m + 1 <= l)
return query_min(l, r, rson);
else //明确min的值是从最左往右加到一个合适的位置的。知道了之后就不难理解。
return min(query_min(l, m, lson), query_sum(l, m, lson) + query_min(m + 1, r, rson));
//min里面的前者相当于不管右区间了。直接求左区间的minlx
//后者则是认为从左区间一直累加到右区间了
} void get_ans()
{
for (int i = 1; i <= m; i++)
{
char op[10];
scanf("%s", op);
int x, y;
char key[5];
if (op[0] == 's')
{
scanf("%d%d%s", &x, &y, key);
x++; y++;
int temp;
if (key[0] == '(')
temp = 1;
else
temp = -1;
up_data(1, x, y, temp, 1, n, 1);
}
else
if (op[0] == 'r')
{
scanf("%d%d", &x, &y);
x++; y++;
up_data(2, x, y, 0, 1, n, 1);
}
else
{
scanf("%d%d", &x, &y);
x++; y++;
int leijia = query_sum(x, y, 1, n, 1);
if (leijia != 0)
printf("NO\n");
else
{
int mi = query_min(x, y, 1, n, 1);
if (mi >= 0)
printf("YES\n");
else
printf("NO\n");
}
}
}
} int main()
{
//freopen("F:\\rush.txt", "r", stdin);
//freopen("F:\\rush_out.txt", "w", stdout);
int t;
scanf("%d", &t);
for (int ii = 1;ii <= t;ii++)
{
printf("Case %d:\n", ii);
input_data();
get_ans();
printf("\n");
}
return 0;
}

【20.95%】【UESTC 94】Bracket Squence的更多相关文章

  1. LeetCode:有效的括号【20】

    LeetCode:有效的括号[20] 题目描述 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. ...

  2. 【20】display,float,position的关系

    [20]display,float,position的关系 如果display为none,元素不显示. 否则,如果position值为absolute或者fixed,元素绝对定位,float的计算值为 ...

  3. 【Android】【录音】Android录音--AudioRecord、MediaRecorder

    [Android][录音]Android录音--AudioRecord.MediaRecorder Android提供了两个API用于实现录音功能:android.media.AudioRecord. ...

  4. 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理

    [微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...

  5. 【Python】【容器 | 迭代对象 | 迭代器 | 生成器 | 生成器表达式 | 协程 | 期物 | 任务】

    Python 的 asyncio 类似于 C++ 的 Boost.Asio. 所谓「异步 IO」,就是你发起一个 IO 操作,却不用等它结束,你可以继续做其他事情,当它结束时,你会得到通知. Asyn ...

  6. day41 python【事物 】【数据库锁】

    MySQL[五] [事物 ][数据库锁]   1.数据库事物 1. 什么是事务  事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消.也就是事务具有原子性 ...

  7. 程序员需要的各种PDF格式电子书【附网盘免费下载资源地址】

    程序员需要的各种PDF格式电子书[附网盘免费下载资源地址]   各位,请妥善保存,后期还会有更多更新,如果你有不同的书籍资源或者这里没有你要找的书籍,也可以直接留言,后期我们会继续更新~ Java & ...

  8. 老男孩Python高级全栈开发工程师【真正的全套完整无加密】

    点击了解更多Python课程>>> 老男孩Python高级全栈开发工程师[真正的全套完整无加密] 课程大纲 老男孩python全栈,Python 全栈,Python教程,Django ...

  9. 【转】从外行的视角尝试讲解为什么这回丰田栽了【全文完】【v1.01】

    转自:http://club.tgfcer.com/thread-6817371-1-1.html  [第一部分]背景简介 前几年闹得沸沸扬扬的丰田刹不住事件最近又有新进展.十月底俄克拉荷马的一次庭审 ...

随机推荐

  1. java通过实体类组装报文

    条件: 1.实体类字段名 首字母小写(java规范),再通过报文的需求,填充的时候做对应修改即可(正常报文首字母是大写的)! 2.假如xml标签首字母是小写,那么实体类就给大写,首字母是大写,那么实体 ...

  2. [已转移]JavaScript事件---DOM事件流

    该文章已转移到博客:https://cynthia0329.github.io/ 事件发生时会在元素节点与根节点之间按照特定的顺序传播,路径所经过的所有节点都会收到该事件 这个传播过程即DOM事件流. ...

  3. HZOJ trade

    强烈谴责$skyh$的没$\Huge 脸$行为. 很经典的可反悔贪心,然而我一直以为是sbdp还一直想着怎么优化…… 正常的贪心肯定是不对的. 但是由于A-C=A-B+B-C, 所以用一个小根堆维护, ...

  4. 【批量添加】-SqlBulkCopy语句 标签: sql批量添加 2015-12-20 14:39 1367人阅读 评论(33)

    上篇博客我们介绍了通过拼接sql字符串的方法来对sql数据库进行批量添加,但是通过语句拼接insert语句有个缺点,就是每次最多只能添加1000条.当时我们另外一个界面也用到了批量添加,但是这个界面轻 ...

  5. laravel进阶系列--通过事件和事件监听实现服务解耦

    简介 Laravel 事件提供了简单的观察着模式实现,允许你订阅和监听应用中的事件.事件类通常存放在 app/Events 目录. 监听器存放在 app/Listeners. 如果你在应用中没有看到这 ...

  6. CNN滤波器

    CNN 的第一步是把图片分成小块.我们通过选取一个给定宽度和高度的滤波器来实现这一步. 滤波器会照在图片的小块 patch (图像区块)上.这些 patch 的大小与滤波器一样大.   如之前视频所示 ...

  7. 解决TortoiseSVN中out of date问题的一个方法

    http://blog.csdn.net/freefalcon/article/details/645058 从去年开始,公司的代码管理从CVS转向了subvsersion,后者确实是前者的一个飞跃, ...

  8. HTML静态网页--表单验证和事件

    1.表单验证<form></form> (1).非空验证(去空格) (2).对比验证(跟一个值对比) (3).范围验证(根据一个范围进行判断) (4).固定格式验证:电话号码, ...

  9. SQL 变量,运算符

    一.变量 SQL语言也跟其他编程语言一样,拥有变量.分支.循环等控制语句. 在SQL语言里面把变量分为局部变量和全局变量,全局变量又称系统变量. (一).局部变量 使用declare关键字给变量声明, ...

  10. 洛谷P2146 [NOI2015]软件包管理器 题解 树链剖分+线段树

    题目链接:https://www.luogu.org/problem/P2146 本题涉及算法: 树链剖分: 线段树(区间更新及求和,涉及懒惰标记) 然后对于每次 install x ,需要将 x 到 ...