【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 [第一部分]背景简介 前几年闹得沸沸扬扬的丰田刹不住事件最近又有新进展.十月底俄克拉荷马的一次庭审 ...
随机推荐
- day16 web前端之JavaScript
页面布局补充 样例页面: 示例代码: <!DOCTYPE html> <html lang="en"> <head> <meta char ...
- SWF在线绘本批量制作高质量PDF的新方法(重点在批量制作)
SWF在线绘本批量制作高质量PDF的新方法(重点在批量制作) 2012-12-21 未来决定... http://www.ebama.net/thread-107643-1-1.html ...
- nodeJs学习-11 multer中间件,解析post文件,上传文件
const express=require('express'); const bodyParser=require('body-parser'); const multer=require('mul ...
- SpringCloud Zuul 路由映射规则配置
阅读目录 前言 快速入门 路由详解 Cookie与头信息 本地跳转 Hystrix和Ribbon支持 过滤器解释 动态加载 后记 回到目录 前言 本文起笔于2018-06-26周二,接了一个这周要完成 ...
- 2019-9-23-dotnet-判断特定进程存在方法
title author date CreateTime categories dotnet 判断特定进程存在方法 lindexi 2019-09-23 16:20:42 +0800 2019-09- ...
- SharpDX初学者教程第2部分:创建窗口
原文 http://www.johanfalk.eu/blog/sharpdx-tutorial-part-2-creating-a-window 在第二篇教程中,我们将介绍如何创建一个稍后将呈现的简 ...
- [***]HZOJ 奇袭
C. 奇袭 题目描述 由于各种原因,桐人现在被困在Under World(以下简称UW)中,而UW马上 要迎来最终的压力测试——魔界入侵. 唯一一个神一般存在的Administrator被消灭了,靠原 ...
- 【BZOJ1227】[SDOI2009]虔诚的墓主人
E. 虔诚的墓主人 题目描述 小W 是一片新造公墓的管理人.公墓可以看成一块N×M 的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地.当地的居民都是非常虔诚的基督徒,他们愿意提前 ...
- oracle 尽量多使用COMMIT
只要有可能,在程序中尽量多使用COMMIT, 这样程序的性能得到提高,需求也会因为COMMIT所释放的资源而减少: COMMIT所释放的资源: a. 回滚段上用于恢复数据的信息. b. ...
- Lists and keys
function NumberList(props) { const numbers = props.numbers; const listItems = numbers.map((number) = ...