洛谷 P3797 妖梦斩木棒 解题报告
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 妖梦斩木棒 解题报告的更多相关文章
- 洛谷P3797 妖梦斩木棒
P3797 妖梦斩木棒 题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看 ...
- 洛谷 P3797 妖梦斩木棒
https://www.luogu.org/problem/show?pid=3797 题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了 ...
- 洛谷P3799 妖梦拼木棒
P3799 妖梦拼木棒 53通过 345提交 题目提供者orangebird 标签 难度普及/提高- 时空限制1s / 128MB 提交 讨论 题解 最新讨论更多讨论 暂时没有讨论 题目背景 上道 ...
- [luogu P3797] 妖梦斩木棒 [线段树]
题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看做由三种小段构成,中间的 ...
- Luogu P3797 妖梦斩木棒
解题思路 用线段树做这个就不用说了吧,但是要维护的东西确实很神奇.在每一个节点上都维护一个$lbkt$,表示这个区间上最靠左的右括号的位置:一个$rbkt$,表示这个区间上最靠右的左括号的位置.还有一 ...
- AC日记——妖梦斩木棒 洛谷 P3797
妖梦斩木棒 思路: 略坑爹: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 200005 #define m ...
- [Luogu3797] 妖梦斩木棒
题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看做由三种小段构成,中间的 ...
- 洛谷 P2323 [HNOI2006]公路修建问题 解题报告
P2323 [HNOI2006]公路修建问题 题目描述 输入输出格式 输入格式: 在实际评测时,将只会有m-1行公路 输出格式: 思路: 二分答案 然后把每条能加的大边都加上,然后加小边 但在洛谷的题 ...
- 洛谷 P1852 [国家集训队]跳跳棋 解题报告
P1852 [国家集训队]跳跳棋 题目描述 跳跳棋是在一条数轴上进行的.棋子只能摆在整点上.每个点不能摆超过一个棋子. 我们用跳跳棋来做一个简单的游戏:棋盘上有3颗棋子,分别在\(a\),\(b\), ...
随机推荐
- Docker容器的启动与停止
启动docker:systemctl start docker 停止docker:systemctl stop docker 重启docker:systemctl restart docker 查看d ...
- UVA 816 Abbott's Revenge 紫书
紫书的这道题, 作者说是很重要. 但看着题解好长, 加上那段时间有别的事, 磨了几天没有动手. 最后,这道题我打了五遍以上 ,有两次被BUG卡了,找了很久才找到. 思路紫书上有,就缺少输入和边界判断两 ...
- Kaggle 广告转化率预测比赛小结
20天的时间参加了Kaggle的 Avito Demand Prediction Challenged ,第一次参加,成绩离奖牌一步之遥,感谢各位队友,学到的东西远比成绩要丰硕得多.作为新手,希望每记 ...
- caffe/blob.hpp:9:34: fatal error: caffe/proto/caffe.pb.h: 没有那个文件或目录
You need to generate caffe.pb.h manually using protoc as follows. # In the directory you installed C ...
- SQL 查一年内的数据
--查询今年的 select * from 表 where datediff(yy,时间字段,GETDATE())=0 --查询去年的 select * from 表 where datediff(y ...
- “Hello World!团队”Final发布—视频链接+文案+美工
视频发布:http://www.bilibili.com/video/av17022373/ 文案加美工:http://www.cnblogs.com/chjy/p/7990116.html SkyH ...
- Myeclipse(2014)项目的注释乱码
(之前都是在项目右键 propertits----resource---text file encoding 里面改成UTF-8的 下面是以后都直接换) window->preference-& ...
- POJ 2096 Collecting Bugs 期望dp
题目链接: http://poj.org/problem?id=2096 Collecting Bugs Time Limit: 10000MSMemory Limit: 64000K 问题描述 Iv ...
- opencv的安装和卸载
安装 测试环境为centos 安装依赖 yum install cmake gcc gcc-c++ gtk2-devel gimp-develgimp-devel-tools gimp-help-br ...
- CountVectorizer,Tf-idfVectorizer和word2vec构建词向量的区别
CountVectorizer和Tf-idfVectorizer构建词向量都是通过构建字典的方式,比如在情感分析问题中,我需要把每一个句子(评论)转化为词向量,这两种方法是如何构建的呢?拿CountV ...