Luogu P3797 妖梦斩木棒
解题思路
用线段树做这个就不用说了吧,但是要维护的东西确实很神奇。在每一个节点上都维护一个$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 妖梦斩木棒的更多相关文章
- [luogu P3797] 妖梦斩木棒 [线段树]
题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看做由三种小段构成,中间的 ...
- 洛谷 P3797 妖梦斩木棒 解题报告
P3797 妖梦斩木棒 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的\(n\)段.现在这个木棒可以看做 ...
- 洛谷P3797 妖梦斩木棒
P3797 妖梦斩木棒 题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看 ...
- 洛谷 P3797 妖梦斩木棒
https://www.luogu.org/problem/show?pid=3797 题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了 ...
- AC日记——妖梦斩木棒 洛谷 P3797
妖梦斩木棒 思路: 略坑爹: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 200005 #define m ...
- luogu P3799 妖梦拼木棒
二次联通门 : luogu P3799 妖梦拼木棒 /* luogu P3799 妖梦拼木棒 用一个桶存下所有的木棒 美剧两根短的木棒长度 后随便乘一乘就 好了.. */ #include <a ...
- [Luogu3797] 妖梦斩木棒
题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看做由三种小段构成,中间的 ...
- 洛谷P3799 妖梦拼木棒
P3799 妖梦拼木棒 53通过 345提交 题目提供者orangebird 标签 难度普及/提高- 时空限制1s / 128MB 提交 讨论 题解 最新讨论更多讨论 暂时没有讨论 题目背景 上道 ...
- P3799 妖梦拼木棒 (组合数学)
题目背景 上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来. 题目描述 有n根木棒,现在从中选4根,想要组成一个正三角形,问有几种选法? 输入输出格式 输入格式: 第一行一个整数n 第二行n个整数 ...
随机推荐
- 洛谷 P1131 [ ZJOI 2007 ] 时态同步 —— 树形DP
题目:https://www.luogu.org/problemnew/show/P1131 记录 x 子树内同步的时间 f[x],同步所需代价 g[x]: 直接转移即可,让该儿子子树与其它儿子同步, ...
- Java 泛型 四 基本用法与类型擦除
简介 Java 在 1.5 引入了泛型机制,泛型本质是参数化类型,也就是说变量的类型是一个参数,在使用时再指定为具体类型.泛型可以用于类.接口.方法,通过使用泛型可以使代码更简单.安全.然而 Java ...
- 35. extjs MessageBox里fn:是什么意思
function的缩写,用来指定回调函数,就是你点击确定或取消按钮之类的按钮以后触发的事件Ext.Msg.show({ title:'自定义消息框', msg:'这是一个自定义消息框,想怎么搞就怎么搞 ...
- maven中的三种工程,以及在idea中构建父子工程。
1.pom工程:用在父级工程或聚合工程中.用来做jar包的版本控制.主要是定义POM文件,将后续各个子模块公用的jar包等统一提出来,类似一个抽象父类 2.war工程:将会打包成war,发布在服务器上 ...
- attr 和 prop的区别和使用
一. attr和prop的区别 要想弄清楚attr和prop的区别,就要先搞清楚js中使用DOM方法获取设置属性和使用对象方法获取设置属性的区别. 在javascript中使用DOM方法设置获取属性值 ...
- 手机访问PC网站自动跳转到手机网站代码
方法一: <script type="text/javascript"> try { var urlhash = window.location.hash; if (! ...
- bzoj 1585: [Usaco2009 Mar]Earthquake Damage 2 地震伤害【最小割】
枚举建图.jpg 一开始建的图挂了,于是枚举了几种建图方式-- 因为要删点,所以拆点,连接(i,i',1),对于原来图上的边(u,v),连接(u',v,inf),(v',u,inf),然后连接(s,i ...
- (DP)51NOD 1049 最大子段和
N个整数组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续子段和的最大值.当所给的整数均为负数时和为0. 例如:-2,11,-4,13,-5 ...
- 转载使用 ContentObsever 拦截短信,获取短信内容
在一些应用上,比如手机银行,QQ,微信等,很多时候我们都需要通过发送验证码到手机上,然后把验证码填上去,然后才能成功地继续去做下面一步事情. 而如果每次我们都要离开当前界面,然后去查收短信,记住验证码 ...
- redis在linux环境下的安装与启动
定义 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted s ...