解题思路

用线段树做这个就不用说了吧,但是要维护的东西确实很神奇。在每一个节点上都维护一个$lbkt$,表示这个区间上最靠左的右括号的位置;一个$rbkt$,表示这个区间上最靠右的左括号的位置。还有一个$sum$,表示这段区间(除去左右端点)上有几段完整的木棒。

注意如果一个区间内没有左右括号的话,那$lbkt=0,rbkt=0$

然后再考虑如何建树。首先想到的是第一个节点,它代表的区间是$1-n$,他的$lbkt$是$n$,$rbkt$是$1$。然后对于包含左右端点的区间进行一下特判,类似于第一个节点的操作,其余的就没啥好说的了,要是再不会就退群吧

这道题目唯一良心的地方就是那个单点修改,还好没给整成区间修改。那我们怎么单点修改呢?因为是单点修改,修改的时候$l=r$,所以可以很容易的确定$lbkt$和$rbkt$。如果是'X'的话,那么这两个值都是$0$。$sum$的维护也不难,修改了之后无非只有两种情况,那就是想修改了之后左右儿子多出了一段木棒。也有可能没有多处,所以只需要把左右儿子的$sum$加起来,再判断修改了之后能不能构成一段新的木棒。

询问也没啥好说的

附上代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define Lson (k << 1)
#define Rson (k << 1) + 1 using namespace std;
const int maxnode = 8e5+;
int n, m;
struct node {
int l, r, sum, lbkt, rbkt;
}tree[maxnode];
inline void build(int k, int ll, int rr) {
tree[k].l = ll, tree[k].r = rr;
if(k == ) { tree[k].sum = , tree[k].lbkt = n, tree[k].rbkt = ; }
else {
tree[k].sum = ;
if(tree[k].l == ) tree[k].rbkt = ;
if(tree[k].r == n) tree[k].lbkt = n;
}
if(tree[k].l == tree[k].r) return ;
int mid = (tree[k].l + tree[k].r) >> ;
build(Lson, tree[k].l, mid), build(Rson, mid+, tree[k].r);
}
inline void update(int k, int x, int y) {
if(tree[k].l == tree[k].r && tree[k].l == x) {
if(y == ) tree[k].rbkt = x, tree[k].lbkt = ;
if(y == ) tree[k].rbkt = , tree[k].lbkt = ;
if(y == ) tree[k].rbkt = , tree[k].lbkt = x;
return ;
}
int mid = (tree[k].l + tree[k].r) >> ;
if(mid >= x) update(Lson, x, y);
if(mid < x) update(Rson, x, y);
tree[k].sum = tree[Lson].sum + tree[Rson].sum;
tree[k].sum += min(tree[Lson].rbkt, ) * min(tree[Rson].lbkt, );
if(tree[Lson].lbkt > ) tree[k].lbkt = tree[Lson].lbkt;
else if(tree[Lson].rbkt == and tree[Lson].sum == )
tree[k].lbkt = tree[Rson].lbkt;
else tree[k].lbkt = ;
if(tree[Rson].rbkt > ) tree[k].rbkt = tree[Rson].rbkt;
else if(tree[Rson].lbkt == and tree[Rson].sum == )
tree[k].rbkt = tree[Lson].rbkt;
else tree[k].rbkt = ;
}
inline int queryl(int k, int l, int r) {
if(tree[k].lbkt <= r && tree[k].lbkt >= l) return tree[k].lbkt;
else return ;
}
inline int queryr(int k, int l, int r) {
if(tree[k].rbkt <= r && tree[k].rbkt >= l) return tree[k].rbkt;
else return ;
}
inline int Query(int k, int l, int r) {
if(tree[k].l > r || tree[k].r < l) return ;
if(tree[k].l >= l && tree[k].r <= r) return tree[k].sum;
int ans = Query(Lson, l, r) + Query(Rson, l, r);
ans += min(queryl(Rson, l, r), ) * min(queryr(Lson, l, r), );
return ans;
} int main() {
scanf("%d%d", &n, &m);
build(, , n);
int x, y, z;
char ch;
for(int i=; i<=m; i++) {
scanf("%d", &z);
if(z == ) {
cin>>x; cin>>ch;
if(ch == '(') y = ;
if(ch == 'X') y = ;
if(ch == ')') y = ;
update(, x, y);
}
else {
cin>>x>>y;
printf("%d\n", Query(, x, y));
}
}
return ;
}

Luogu P3797 妖梦斩木棒的更多相关文章

  1. [luogu P3797] 妖梦斩木棒 [线段树]

    题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看做由三种小段构成,中间的 ...

  2. 洛谷 P3797 妖梦斩木棒 解题报告

    P3797 妖梦斩木棒 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的\(n\)段.现在这个木棒可以看做 ...

  3. 洛谷P3797 妖梦斩木棒

    P3797 妖梦斩木棒 题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看 ...

  4. 洛谷 P3797 妖梦斩木棒

    https://www.luogu.org/problem/show?pid=3797 题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了 ...

  5. AC日记——妖梦斩木棒 洛谷 P3797

    妖梦斩木棒 思路: 略坑爹: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 200005 #define m ...

  6. luogu P3799 妖梦拼木棒

    二次联通门 : luogu P3799 妖梦拼木棒 /* luogu P3799 妖梦拼木棒 用一个桶存下所有的木棒 美剧两根短的木棒长度 后随便乘一乘就 好了.. */ #include <a ...

  7. [Luogu3797] 妖梦斩木棒

    题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看做由三种小段构成,中间的 ...

  8. 洛谷P3799 妖梦拼木棒

    P3799 妖梦拼木棒 53通过 345提交 题目提供者orangebird 标签 难度普及/提高- 时空限制1s / 128MB 提交  讨论  题解 最新讨论更多讨论 暂时没有讨论 题目背景 上道 ...

  9. P3799 妖梦拼木棒 (组合数学)

    题目背景 上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来. 题目描述 有n根木棒,现在从中选4根,想要组成一个正三角形,问有几种选法? 输入输出格式 输入格式: 第一行一个整数n 第二行n个整数 ...

随机推荐

  1. 通过shell脚本批处理es数据

    #!/bin/sh [按照指定的域名-website集合,遍历各个域名,处理url] #指定待删除的变量集合 arr=(6.0) cur="`date +%Y%m%d%H%M%S`" ...

  2. web metrics dashboard 数据分析工具 看板 从可视化发现问题 避免sql重复写 调高效率

    <?php$todo = array();$done = array();$h = array();$v = $all['v'];$l = count($v);#19700101 08for ( ...

  3. 双层for 循环

    说说 图片 集合 list(set([ii for i in img_url_l for ii in i[0].replace('[','').replace(']','').replace(&quo ...

  4. beego3---gohttp底层实现

    package main //gohttp底层实现,通过gohttp不是通过beego实现的输出 // import ( "io" "log" "ne ...

  5. Kettle 连接 oracle 报错:could not be found, make sure the 'Oracle' driver (jar file) is installed.

    我的ETL版本为6.0 oracle版本为11.2.0 报错如下: Driver class 'oracle.jdbc.driver.OracleDriver' could not be found, ...

  6. ssh使用秘钥文件连接提示WARNING: UNPROTECTED PRIVATE KEY FILE!(转载)

    转自:http://www.01happy.com/ssh-unprotected-private-key-file/ 在centos 6.4下使用ssh连接远程主机时,用的是另外一个密钥,需要用-i ...

  7. Linux常用命令分类

    目录:相对路径和绝对路径. 绝对路径:路径的写法[一定由根目录 / 写起],例如: /usr/share/doc 这个目录. 相对路径:路径的写法[不是由 / 写起],例如由 /usr/share/d ...

  8. 最常用的~正则表达式-相关js函数知识简洁分享【新手推荐】

    一.正则表达式的创建 JS正则的创建有两种方式: new RegExp() 和 直接字面量. //使用RegExp对象创建 varregObj =newRegExp("(^\s+)|(\s+ ...

  9. HTML和JSP的不同及优缺点

    HTML(Hypertext Markup Language)文本标记语言,它是静态页面,和JavaScript一样解释性语言,为什么说是解释性语言呢?因为,只要你有一个浏览器那么它就可以正常显示出来 ...

  10. [Usaco2005 oct]Flying Right 飞行航班

    Description 为了表示不能输给人类,农场的奶牛们决定成立一家航空公司.她们计划每天早晨,从密歇根湖湖岸的最北端飞向最南端,晚上从最南端飞往最北端.在旅途中,航空公司可以安排飞机停在某些机场. ...