题目大意:给定一个合法的括号序列(只包含'(',')'),有q次操作,对每次操作改变一个位置的括号,求最左端的位置,使得改变这个位置上的括号以后,新序列合法(完全配对)。

思路:对于合法的括号序列,如果把括号序列一次进行栈操作,把'('进栈,')'则把最近的'('出栈,令a[i]表示到i位置后栈里面的左括号个数,也就是i位置的左括号数目和右括号数目的差。则原序列对应新的数组a。原序列合法 等价于 对于1<=i<=n,a[i]>=0 恒成立。那么对于把位置pos上的括号改变一下,如果是'(' - ')',那么a[pos~n]会都减去2,如果是')'->'(',那么a[pos~n]会都加上2。分类讨论后,答案不难得出。对于'('->')'答案就是从左至右找第一个右括号;对于')'->'(',答案就是找一个最左端的位置pos0,使得a[pos0~pos-1]都大于等于2。对于找第一个右括号,可以转化为用新的数组b[i] = a[i] - i,找第一个小于0的位置,进而转化为找最大的前缀区间使得这个区间上的b的最小值等于0。对于找最左端的位置,也可以转化为区间最值来做,详见代码:

 #include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <queue>
#include <cmath>
#include <vector>
#include <ctime>
#define mem0(a) memset(a, 0, sizeof(a))
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define define_m int m = (l + r) >> 1
#define LL long long
#define Rep(a, b) for(int a = 0; a < b; a++)
#define lowbit(x) ((x) & (-(x)))
const int dx[] = {, , -, };
const int dy[] = {, -, , };
const int INF = 1e9 + ;
const int maxn = ;
const double eps = 1e-;
typedef double db;
using namespace std;
struct SegTree {
struct Node {
int minv, add;
} tree[maxn << ];
void PushUp(int rt) {
tree[rt].minv = min(tree[rt << ].minv, tree[rt << | ].minv);
}
void PushDown(int rt) {
int add = tree[rt].add;
if (add) {
tree[rt << ].minv += add;
tree[rt << ].add += add;
tree[rt << | ].minv += add;
tree[rt << | ].add += add;
tree[rt].add = ;
}
}
void Build(int a[], int l, int r, int rt) {
tree[rt].add = ;
if (l == r) {
tree[rt].minv = a[l];
return ;
}
define_m;
Build(a, lson);
Build(a, rson);
PushUp(rt);
}
void Update(int L, int R, int x, int l, int r, int rt) {
if (L <= l && r <= R) {
tree[rt].minv += x;
tree[rt].add += x;
return;
}
define_m;
PushDown(rt);
if (L <= m) Update(L, R, x, lson);
if (R > m) Update(L, R, x, rson);
PushUp(rt);
}
int Query1(int l, int r, int rt) {
if (l == r) return tree[rt].minv == ;
define_m;
PushDown(rt);
if (tree[rt << ].minv < ) return Query1(lson);
int len = r - l + ;
return len - (len >> ) + Query1(rson);
}
int Query2(int l, int r, int rt) {
if (l == r) return tree[rt].minv == ;
define_m;
PushDown(rt);
if (tree[rt << | ].minv < ) return Query2(rson);
int len = r - l + ;
return (len >> ) + Query2(lson);
}
};
int n, q;
char s[];
int a[], b[], c[];
SegTree G, H;
void Init() {
for (int i = ; i < n; i++) {
c[i + ] = c[i];
if (s[i] == '(') c[i + ]++;
else c[i + ]--;
}
for (int i = ; i <= n; i++) {
a[i] = c[i] - i;
b[i] = c[i];
}
}
int main() {
//freopen("in.txt", "r", stdin);
cin >> n >> q;
scanf("%s", s);
Init();
G.Build(a, , n, );
H.Build(b, , n, );
for (int i = ; i < q; i++) {
int pos, tmp;
scanf("%d", &pos);
if (s[pos - ] == '(') {
s[pos - ] = ')';
G.Update(pos, n, -, , n, );
H.Update(pos, n, -, , n, );
printf("%d\n", tmp = G.Query1(, n, ) + );
G.Update(tmp, n, , , n, );
H.Update(tmp, n, , , n, );
s[tmp - ] = '(';
}
else {
s[pos - ] = '(';
H.Update(pos, n, , , n, );
G.Update(pos, n, , , n, );
printf("%d\n", tmp = n - H.Query2(, n, ) + );
H.Update(tmp, n, -, , n, );
G.Update(tmp, n, -, , n, );
s[tmp - ] = ')';
}
}
return ;
}

【csu oj 1542】线段树的更多相关文章

  1. hdu 1542 线段树扫描(面积)

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  2. luogu P3285 [SCOI2014]方伯伯的OJ splay 线段树

    LINK:方伯伯的OJ 一道稍有质量的线段树题目.不写LCT splay这辈子是不会单独写的 真的! 喜闻乐见的是 题目迷惑选手 \(op==1\) 查改用户在序列中的位置 题目压根没说位置啊 只有排 ...

  3. hdu 1542 线段树+扫描线 学习

    学习扫描线ing... 玄学的东西... 扫描线其实就是用一条假想的线去扫描一堆矩形,借以求出他们的面积或周长(这一篇是面积,下一篇是周长) 扫描线求面积的主要思想就是对一个二维的矩形的某一维上建立一 ...

  4. 玲珑oj 1117 线段树+离线+离散化,laz大法

    1117 - RE:从零开始的异世界生活 Time Limit:1s Memory Limit:256MByte Submissions:438Solved:68 DESCRIPTION 486到了异 ...

  5. CSUOJ 1542 线段树解决括号反向问题

    题目大意: 根据初始给定的合法的小括号排序,每次进行一个操作,将第a位的括号反向,找到一个尽可能靠前的括号反向后是整个括号排列合法 数据量十分大,不断进行查询,要用线段树进行logn的复杂度的查询 首 ...

  6. hdu 1542 线段树之扫描线之面积并

    点击打开链接 题意:给你n个矩形,求它们的面积,反复的不反复计算 思路:用线段树的扫描线完毕.将X坐标离散化后,从下到上扫描矩形,进行各种处理,看代码凝视把 #include <stdio.h& ...

  7. Atlantis HDU - 1542 线段树+扫描线 求交叉图形面积

    //永远只考虑根节点的信息,说明在query时不会调用pushdown //所有操作均是成对出现,且先加后减 // #include <cstdio> #include <cstri ...

  8. HDU 1542 线段树离散化+扫描线 平面面积计算

    也是很久之前的题目,一直没做 做完之后觉得基本的离散化和扫描线还是不难的,由于本题要离散x点的坐标,最后要计算被覆盖的x轴上的长度,所以不能用普通的建树法,建树建到r-l==1的时候就停止,表示某段而 ...

  9. HDU 1542 线段树+扫描线+离散化

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

随机推荐

  1. Spark SQL源码剖析(一)SQL解析框架Catalyst流程概述

    Spark SQL模块,主要就是处理跟SQL解析相关的一些内容,说得更通俗点就是怎么把一个SQL语句解析成Dataframe或者说RDD的任务.以Spark 2.4.3为例,Spark SQL这个大模 ...

  2. linux之cat 操作

    1.查看或创建 cat 1.txt #如果目录有这个文件则会打开查看,没有则会创建 2.压缩空白 cat 1.txt 我是第一行 我是第二 行 cat -bs 1.txt # 变成 cat 1.txt ...

  3. Apache solr velocity模块 漏洞复现

    0x01 Solr简单介绍 Solr是建立在Apache Lucene ™之上的一个流行.快速.开放源代码的企业搜索平台. Solr具有高度的可靠性,可伸缩性和容错能力,可提供分布式索引,复制和负载平 ...

  4. Java 多线程 -- volatile 山寨版的synchronized

    在 多线程中,每个线程会把数据从主内存中拷贝到自己的工作内存中,当线程完成计算后,再把工作内存的数据更新到主内存中,或者当主内存主数据有更新是,线程会去主内存取最新数据.但是,当线程特别忙时,就不会去 ...

  5. 线程Event

    版本一: from threading import Event,current_thread,Thread import time event=Event() #造一个对象,内部维护一个全局变量,状 ...

  6. 只会Vue怎么开发小程序?vue和微信小程序的到底有哪些区别?

    写了vue项目和小程序,发现二者有许多相同之处,在此想总结一下二者的共同点和区别. 一.生命周期 先贴两张生命周期图对比下: vue生命周期 小程序生命周期 相比之下,小程序的钩子函数要简单得多. v ...

  7. 关于用C-free进行C语言编程在电脑中生成的.exe和.o文件

    在使用C-free进行C语言编程时,程序运行后会自动在电脑文件中生成以.exe和.o为后缀名的文件: 1,生成的.exe文件为系统自动打包完成的应用程序,该程序可直接在其他无C-free环境的电脑上运 ...

  8. 自建Git服务器 - 创建属于你自己的代码仓库

    最近有线上朋友私信问我怎么搭建个人博客,也有咨询我个人项目的代码是如何保管的,还有一个朋友问我买了服务器玩了一段时间,等新鲜感过了就不知道做什么了. 关于这些问题并没有一个标准答案,每个人都有自己的使 ...

  9. LNMP企业应用部署全过程(基于DEDE后台)

    系统环境说明: os:centos 5.6 nginx:nginx-1.0.11 php:php-5.3.9 mysql:mysql-5.5.20 文档导读: 一 准备工作 二 基础软件包安装 三 安 ...

  10. Openstack HA集群5-Keystone HA

    # yum install -y openstack-keystone httpd mod_wsgi # mysql -u root -p -e "CREATE DATABASE keyst ...