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. Docker容器的启动与停止

    启动docker:systemctl start docker 停止docker:systemctl stop docker 重启docker:systemctl restart docker 查看d ...

  2. UVA 816 Abbott's Revenge 紫书

    紫书的这道题, 作者说是很重要. 但看着题解好长, 加上那段时间有别的事, 磨了几天没有动手. 最后,这道题我打了五遍以上 ,有两次被BUG卡了,找了很久才找到. 思路紫书上有,就缺少输入和边界判断两 ...

  3. Kaggle 广告转化率预测比赛小结

    20天的时间参加了Kaggle的 Avito Demand Prediction Challenged ,第一次参加,成绩离奖牌一步之遥,感谢各位队友,学到的东西远比成绩要丰硕得多.作为新手,希望每记 ...

  4. 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 ...

  5. SQL 查一年内的数据

    --查询今年的 select * from 表 where datediff(yy,时间字段,GETDATE())=0 --查询去年的 select * from 表 where datediff(y ...

  6. “Hello World!团队”Final发布—视频链接+文案+美工

    视频发布:http://www.bilibili.com/video/av17022373/ 文案加美工:http://www.cnblogs.com/chjy/p/7990116.html SkyH ...

  7. Myeclipse(2014)项目的注释乱码

    (之前都是在项目右键 propertits----resource---text file encoding 里面改成UTF-8的 下面是以后都直接换) window->preference-& ...

  8. POJ 2096 Collecting Bugs 期望dp

    题目链接: http://poj.org/problem?id=2096 Collecting Bugs Time Limit: 10000MSMemory Limit: 64000K 问题描述 Iv ...

  9. opencv的安装和卸载

    安装 测试环境为centos 安装依赖 yum install cmake gcc gcc-c++ gtk2-devel gimp-develgimp-devel-tools gimp-help-br ...

  10. CountVectorizer,Tf-idfVectorizer和word2vec构建词向量的区别

    CountVectorizer和Tf-idfVectorizer构建词向量都是通过构建字典的方式,比如在情感分析问题中,我需要把每一个句子(评论)转化为词向量,这两种方法是如何构建的呢?拿CountV ...