【20.95%】【UESTC 94】Bracket Squence
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
Status
There is a sequence of brackets, which supports two kinds of operations.
- we can choose a interval [l,r][l,r],
and set all the elements range in this interval to left bracket or right bracket. - 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
, so he want to know whether a interval [l,r][l,r] of
Sequence
the sequence is regular or not after doing some operations.
Let us define a regular brackets sequence in the following way:
- Empty sequence is a regular sequence.
- If
S
is a regular sequence, then(S)
is
also a regular sequences. - If
A
andB
are
regular sequences, thenAB
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 |
Case 1: |
Hint
Huge input, use scanf
instead
of cin
.
Source
【题解】
给你一段括号序列。
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的更多相关文章
- LeetCode:有效的括号【20】
LeetCode:有效的括号[20] 题目描述 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效. 有效字符串需满足: 左括号必须用相同类型的右括号闭合. ...
- 【20】display,float,position的关系
[20]display,float,position的关系 如果display为none,元素不显示. 否则,如果position值为absolute或者fixed,元素绝对定位,float的计算值为 ...
- 【Android】【录音】Android录音--AudioRecord、MediaRecorder
[Android][录音]Android录音--AudioRecord.MediaRecorder Android提供了两个API用于实现录音功能:android.media.AudioRecord. ...
- 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理
[微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...
- 【Python】【容器 | 迭代对象 | 迭代器 | 生成器 | 生成器表达式 | 协程 | 期物 | 任务】
Python 的 asyncio 类似于 C++ 的 Boost.Asio. 所谓「异步 IO」,就是你发起一个 IO 操作,却不用等它结束,你可以继续做其他事情,当它结束时,你会得到通知. Asyn ...
- day41 python【事物 】【数据库锁】
MySQL[五] [事物 ][数据库锁] 1.数据库事物 1. 什么是事务 事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消.也就是事务具有原子性 ...
- 程序员需要的各种PDF格式电子书【附网盘免费下载资源地址】
程序员需要的各种PDF格式电子书[附网盘免费下载资源地址] 各位,请妥善保存,后期还会有更多更新,如果你有不同的书籍资源或者这里没有你要找的书籍,也可以直接留言,后期我们会继续更新~ Java & ...
- 老男孩Python高级全栈开发工程师【真正的全套完整无加密】
点击了解更多Python课程>>> 老男孩Python高级全栈开发工程师[真正的全套完整无加密] 课程大纲 老男孩python全栈,Python 全栈,Python教程,Django ...
- 【转】从外行的视角尝试讲解为什么这回丰田栽了【全文完】【v1.01】
转自:http://club.tgfcer.com/thread-6817371-1-1.html [第一部分]背景简介 前几年闹得沸沸扬扬的丰田刹不住事件最近又有新进展.十月底俄克拉荷马的一次庭审 ...
随机推荐
- js简单倒计时
不想每次用倒计时,都现写代码,比较烦,这里记一下,也顺便分享一些倒计时简单的逻辑. 如果你有更简单方便的代码,可以分享给大家. var method = { countdownObj: { timer ...
- 从 Program Manager 看 Leader 是什么角色
http://blog.csdn.net/uxyheaven/article/details/50396951 从 Program Manager 看 Leader 是什么角色 转载请注明出处http ...
- 集合--Collection接口详解&&迭代器
/* * 集合的顶层接口--Collection接口 * 添加 * add() * addAll() * * 遍历集合 * iterator() 迭代器 * * 删除 * remove() * rem ...
- 【JZOJ4854】【NOIP2016提高A组集训第6场11.3】小澳的坐标系
题目描述 小澳者表也,数学者景也,表动则景随矣. 小澳不喜欢数学,可数学却待小澳如初恋,小澳睡觉的时候也不放过. 小澳的梦境中出现了一个平面直角坐标系,自原点,向四方无限延伸. 小澳在坐标系的原点,他 ...
- day4_python之名称空间与作用域、闭包函数、嵌套函数
一.名称空间与作用域 名称空间:存放名字的地方,准确的说名称空间是存放名字与变量值绑定关系的地方 内置名称空间:在python解释器启动时产生,存放一些python内置的名字 全局名称空间:在执行文件 ...
- hdu4318 最短路变形
和hdu有一题差不多.给的是损失比,1-c%就是保存了多少,找出最大的保存率即可. #include<stdio.h> #include<iostream> #include& ...
- [linux]jenkins迁移 标签: linux服务器 2016-08-28 21:29 988人阅读 评论(20)
我们的测试的jenkins和开发的jenkins 是分开的两个jenkins,然后测试的jenkins很久没有用,我们打算把主节点搬到另外一条服务器上面,然后出了一系列的问题,如下: 一.安装jenk ...
- 转载 LibGDX: 使用 Gradle 命令运行和打包项目
版权声明:本文为csdn xietansheng 博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接: http://blog.csdn.net/xieta ...
- hdu 2412 Party at Hali-Bula【树形dp】
HDU 2412 和poj 2342(hdu 1520)差不多,多了一个判断最优解是(Yes)否(No)唯一.关键问题也在这个判断最优解是否唯一上. 先定义dp[u][2],表示选(dp[][1])或 ...
- Redis源码解析:06整数集合
整数集合(intset)是集合键的底层实现之一,当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis就会使用整数集合作为集合键的底层实现. intset可以保存类型为int16_t,i ...