【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
Sis a regular sequence, then(S)is
also a regular sequences. - If
AandBare
regular sequences, thenABis 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 [第一部分]背景简介 前几年闹得沸沸扬扬的丰田刹不住事件最近又有新进展.十月底俄克拉荷马的一次庭审 ...
随机推荐
- Directx11教程(34) 纹理映射(4)
原文:Directx11教程(34) 纹理映射(4) 本篇教程中,我们尝试在myTutorialD3D_27中改变采样状态描述符的各种设置,看纹理贴图的方式有什么变化. 原始的代码是: ...
- 跟我一起认识axure(二)
创建企业网站页面步骤 第一步修改这里 变成 第一部分就完成了 第二部分部件窗口 在Axure中设计页面像小时候玩的拼图游戏,那么部件窗口就是专门用来存放拼图块的容器 使用部件窗口中常用的部件设计欢迎页 ...
- 比较全面的一个PHP缓存类解析
转自:http://www.blhere.com/1164.html 一.引论 PHP,一门最近几年兴起的web设计脚本语言,由于它的强大和可伸缩性,近几年来得到长足的发展,php相比传统的asp网站 ...
- 发布网站时 遇到XX类型 同时存在XX.dll和XX.dll中
遇到该问题的可能如下: 1.复制了页面 更改了名字 可是对应的一些地方没有注意 <%@ Page Language="C#" AutoEventWireup="tr ...
- SDUT-2124_基于邻接矩阵的广度优先搜索遍历
数据结构实验之图论一:基于邻接矩阵的广度优先搜索遍历 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 给定一个无向连通图 ...
- 03搭建docker私有仓库
搭建docker私仓,可以使用docker官方提供的registry镜像.该镜像目前有2.0,2.3和2.3.1版本.它只与1.6.0以上版本的docker兼容.搭建私仓的步骤如下: 一:无代理.无认 ...
- 行为面试法(STAR)
从过去的行为预测未来,是一种提问技巧. 情景 : Situation 当时怎么了 当时你所在团队主要销售任务是什么目标 : Task 你要干什么 当时你的销售业绩是多少行动 : Action 你都干了 ...
- docker compose安装gitea
docker-compose.yml version: "3.4" networks: gitea: external: false services: server: image ...
- 洛谷P1164 小A点菜
//求方案数 定义状态f[i][j] 用前i件物品恰好放够体积为j的背包 方案数 #include<bits/stdc++.h> using namespace std; ; ; int ...
- vlc 网页插件的 使用与控制 API
下面开始使用教程: html文档结构: <object class="vlc" type='application/x-vlc-plugin' events='True' w ...