洛谷 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\), ...
 
随机推荐
- 1.21 贪心入门上午PAT例题题解
			
1.B1023 #include<cstdio> int a[10]; int main() { for(int i=0;i<=9;i++) { scanf("%d&quo ...
 - docker 安装vim
			
执行以下命令 apt-get update apt-get install vim
 - gcc 与 g++的区分较
			
一:gcc与g++比较 误区一:gcc只能编译c代码,g++只能编译c++代码两者都可以,但是请注意:1.后缀为.c的,gcc把它当作是C程序,而g++当作是c++程序:后缀为.cpp的,两者都会认为 ...
 - 分布式消息队列RocketMQ与Kafka架构上的巨大差异
			
分布式消息服务 Kafka 是一个高吞吐.高可用的消息中间件服务,适用于构建实时数据管道.流式数据处理.第三方解耦.流量削峰去谷等场景,具有大规模.高可靠.高并发访问.可扩展且完全托管的特点,是分布式 ...
 - 【树莓派】crontab的两个问题
			
1,/var/log下面,没有cron.log日志 root@raspberrypi:/# nano /etc/rsyslog.conf …… …… ############### #### RULE ...
 - import 导入包的特别用法总结
			
指定别名 可以为包指定一个别名,以便记忆或提高输入效率 如 import str "strings" 在使用的时候可以直接使用别名,如原先要写成strings.Contains,现 ...
 - html , body , margin , overflow 之大乱战
			
<!DOCTYPE html> <html> <head> <style> html,body{ margin:0 ;padding:0 } div{m ...
 - host命令详解
			
基础命令学习目录首页 原文链接:https://blog.csdn.net/xin_y/article/details/53924763 分析域名查询工具,测试域名系统工作是否正常 语法: host ...
 - 第十一次ScrumMeeting博客
			
第十一次ScrumMeeting博客 本次会议于11月29日(三)22时整在3公寓725房间召开,持续30分钟. 与会人员:刘畅.辛德泰张安澜.赵奕.方科栋. 1. 每个人的工作(有Issue的内容和 ...
 - textarea拖拽控制
			
一.用处 textarea默认时允许用户以拖拽形式来改变textarea大小,但textarea的大小变化会撑大其父节点,有时会破坏整体布局,有时我们并不希望textarea随意拖拽. forklif ...