P3797 妖梦斩木棒

妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力。

题目描述

有一天,妖梦正在练习剑术。地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的\(n\)段。现在这个木棒可以看做由三种小段构成,中间的n-2段都是左右都被切断的断头,我们记做’\(X\)’,最左边的一段和最右边的一段各有一个圆头,记做’(‘和’)’。幽幽子吃饱后闲来无事,决定戏弄一下妖梦。她拿来了许多这样的三种小段木棒,来替换掉妖梦切下来的n段中的一部分,然后问妖梦一些问题。这些操作可以这样描述:

\(1\) \(x\) \(C\) 将第\(x\)个小段的木棒替换成\(C\)型,C只会是’\(X\)’,’\((\)‘,’\()\)’中的一种

\(2\) \(l\) \(r\) 询问妖梦从第\(l\)段到第\(r\)段之间(含\(l\),\(r\)),有多少个完整的木棒

完整的木棒左右两端必须分别为’(‘和’)’,并且中间要么什么都没有,要么只能有’\(X\)’。

虽然妖梦能够数清楚这些问题,但幽幽子觉得她回答得太慢了,你能教给妖梦一个更快的办法吗?

输入输出格式

输入格式:

第一行两个整数\(n\),\(m\),\(n\)表示共有\(n\)段木棒,\(m\)表示有\(m\)次操作。

木棒的初始形状为(XXXXXX......XXXXXX)。

接下来\(m\)行,每行三个整数/字符,用空格隔开。第一个整数为1或2,表示操作的类型,若类型为1,则接下来一个整数x,一个字符C。若类型为2,接下来两个整数\(l\),\(r\)。含义见题目描述。

输出格式:

对于每一个操作2,输出一行一个整数,表示对应询问的答案。

说明

对于30%的数据,1<=n,m<=1000

对于100%的数据,1<=n,m<=200000

by-orangebird


拍了一下午总算搞出来了,太毒了。

首先说一下思想,其实大概一看大家都会想到拿线段树维护,但实际上没见过类似的模型是比较难想到正解的。

我个人认为,这个维护是有一点分治的思想的(不过线段树其实也是分治的思想了emmm)

在线段树的区间里维护3个值\(dat,L,R\),分别代表区间木棍数量,最左边的右括号的坐标(没有为即为0),最右边的左括号的坐标(没有即为n+1)

对询问

左儿子的+右儿子的+合并时可能产生的一个

对修改

\(dat\)域和询问一样

\(L\)和\(R\)一样,说一个吧

比如\(L\),先拿左儿子更新,如果没更新成功(指没有左儿子括号)再尝试右儿子更新

卡点就在什么时候更新上。当然可以维护一个额外的域去判断,但不加一个额外的域时还是很坑的。。。

不直接说更新方法了,想不出来可以直接看看代码


Code:

#include <cstdio>
#define ls id<<1
#define rs id<<1|1
const int N=200010;
int n,m;
int dat[N<<2],L[N<<2],R[N<<2];
void change(int id,int l,int r,int x,int delta)
{
if(l==r)
{
L[id]=0;R[id]=n+1;
if(delta==1)//'('
R[id]=l;//最右边的左括号
else if(delta==2)//')'
L[id]=r;//最左边的右括号
return;
}
int mid=l+r>>1;
if(x<=mid)
change(ls,l,mid,x,delta);
else
change(rs,mid+1,r,x,delta);
dat[id]=dat[ls]+dat[rs]+(R[ls]<=n&&L[rs]);
L[id]=L[ls];
//如果左儿子没有左括号和右括号就可以考虑用右儿子的右括号了
if(dat[ls]==0&&R[ls]==n+1&&L[ls]==0)
L[id]=L[rs];
R[id]=R[rs];
if(dat[rs]==0&&L[rs]==0&&R[rs]==n+1)
R[id]=R[ls];
}
int query(int id,int l,int r,int ll,int rr)
{
if(l==ll&&r==rr)
return dat[id];
int mid=ll+rr>>1;
if(r<=mid)
return query(ls,l,r,ll,mid);
else if(l>mid)
return query(rs,l,r,mid+1,rr);
else
return query(ls,l,mid,ll,mid)+query(rs,mid+1,r,mid+1,rr)+(R[ls]<=n&&L[rs]&&R[ls]>=l&&L[rs]<=r);
}
void build(int id,int l,int r)
{
L[id]=0,R[id]=n+1;
if(l==1) R[id]=1;//最右边的左括号位置为1
if(r==n) L[id]=n;//最左边的右括号位置为n
if(l==r) return;
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
}
int main()
{
//freopen("data.in","r",stdin);
//freopen("wr.out","w",stdout);
scanf("%d%d",&n,&m);
int opt,l,r;char c;
dat[1]=1;
build(1,1,n);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&opt,&l);
if(opt==1)
{
scanf(" ");
scanf("%c",&c);
if(c=='X') change(1,1,n,l,0);
else if(c=='(') change(1,1,n,l,1);
else change(1,1,n,l,2);
}
else
{
scanf("%d",&r);
printf("%d\n",query(1,l,r,1,n));
}
}
return 0;
}

2018.7.9

洛谷 P3797 妖梦斩木棒 解题报告的更多相关文章

  1. 洛谷P3797 妖梦斩木棒

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

  2. 洛谷 P3797 妖梦斩木棒

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

  3. 洛谷P3799 妖梦拼木棒

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

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

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

  5. Luogu P3797 妖梦斩木棒

    解题思路 用线段树做这个就不用说了吧,但是要维护的东西确实很神奇.在每一个节点上都维护一个$lbkt$,表示这个区间上最靠左的右括号的位置:一个$rbkt$,表示这个区间上最靠右的左括号的位置.还有一 ...

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

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

  7. [Luogu3797] 妖梦斩木棒

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

  8. 洛谷 P2323 [HNOI2006]公路修建问题 解题报告

    P2323 [HNOI2006]公路修建问题 题目描述 输入输出格式 输入格式: 在实际评测时,将只会有m-1行公路 输出格式: 思路: 二分答案 然后把每条能加的大边都加上,然后加小边 但在洛谷的题 ...

  9. 洛谷 P1852 [国家集训队]跳跳棋 解题报告

    P1852 [国家集训队]跳跳棋 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在\(a\),\(b\), ...

随机推荐

  1. Netty源码分析第1章(Netty启动流程)---->第3节: 服务端channel初始化

    Netty源码分析第一章:Netty启动流程   第三节:服务端channel初始化 回顾上一小节的initAndRegister()方法: final ChannelFuture initAndRe ...

  2. Netty源码分析第5章(ByteBuf)---->第2节: ByteBuf的分类

    Netty源码分析第五章: ByteBuf 第二节: ByteBuf的分类 上一小节简单介绍了AbstractByteBuf这个抽象类, 这一小节对其子类的分类做一个简单的介绍 ByteBuf根据不同 ...

  3. 如何通过阿里云APP进行域名备案?阿里云备案流程需要多久?

    如何通过阿里云APP进行域名备案? 1.准备备案材料(很多初次使用阿里云APP进行备案的同学会问备案需要准备哪些资料,不二版本下面就给大家一一列举出来) 个人备案需要材料: ⑴<用户网站备案授权 ...

  4. 笨办法学Python - 习题4: Variables and Names

    1.习题 4: 变量(variable)和命名 学习目标:了解Python中变量的定义,学习定义简明易记的变量名 变量:变量是存储内存中的值,就是每定义一个变量就会在内存中开辟一个空间.基于变量的类型 ...

  5. Linux shell中&,&&,|,||的用法

    前言 在玩dvwa的命令注入漏洞的时候,遇到了没有预料到的错误,执行 ping 127.0.0.1 & echo "<?php phpinfo(); ?>" & ...

  6. xocde missing file 解决方法

    创建一个警告里丢失的文件 托到警报的目录下 重启xcode 警告消失 在xcode中选中这个文件右键delete再次删掉文件,就OK了.

  7. 转载---VisualStudioCode通过SSH远程编辑文件

    最近需要长期修改远端服务器上的代码,调试.vim操作又不是很6,想到了远程操作的办法,找到一篇好用的bolg,记录一下. 原文链接:https://blog.csdn.net/qq_38401919/ ...

  8. Linux基础入门--06

    简单的文本处理 实验介绍 这一节我们将介绍这几个命令:tr.col.join.paste 1.tr: -d:删除和set1匹配的字符,不是全词匹配也不是按字符顺序匹配 -s:除去指定的连续并重复的字符 ...

  9. 第二阶段Sprint6

    昨天:设置统一保存路径为内存卡,实现可以选择播放已有的视频 今天:将“录制”及“保存”整合到一起,修复出现的Bug,使之能够正常运行. 遇到的问题:感觉调的摄像头录制的画面不好,这怎么办啊?

  10. 《Spring1之第七次站立会议》

    <第七次站立会议> 昨天:我把自己项目工程里的服务器端界面进行了优化和完善. 今天:我查找了关于实现视频功能的相关代码. 遇到的问题:找到的都是基于C#的相关代码,很难找到用java实现的 ...