妖梦斩木棒

题目背景

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

题目描述

有一天,妖梦正在练习剑术。地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的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,输出一行一个整数,表示对应询问的答案。

输入输出样例

输入样例#1:

4 4
2 1 4
2 2 4
1 2 (
2 2 4

输出样例#1:

1
0
1

说明

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

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

by-orangebird

线段树

对于每一个区间,维护是否向左开c[rt].ls(右括号左边无木棍),是否向右开c[rt].rs(左括号右边无棍)

再维护是否为空c[rt].ps(用处:合并时,c[rt*2].ps&&c[rt*2+1].ls→c[rt].ls=1)

还维护完整木棍数才c[rt].sum;合并时c[rt*2].rs&&c[rt*2+1].ls→c[rt].sum=c[rt*2].sum+c[rt*2+1].sum+1;

注意查询时,不能直接返回c[rt].sum并求和。因为会多算或少算。要返回所有维护信息,再把解合并

如查询1-7(红色为返回c[rt].sum的节点),ans=1,但明显ans应等于2,应为返回时忽略了左右单独括号的合并

                    (xx)()(xx)

              (xx)(              )(xx)

                                  )(x     x)   

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct Messi
{
    int ls,rs,sum,ps;
}c[800001];
int n,m;
Messi merge(Messi a,Messi b)
{
    Messi x;
    x.ps=a.ps&b.ps;
    x.ls=a.ps?b.ls:a.ls;
    x.rs=b.ps?a.rs:b.rs;
    x.sum=a.sum+b.sum;
    if (b.ls&&a.rs&&!b.ps&&!a.ps) x.sum++;
    return x;
}
void build(int rt,int l,int r)
{
    if (l==r)
     {
         if (l==1)
         {
          c[rt].rs=1;
          c[rt].ps=0;
          c[rt].ls=0;
         }
         else if (r==n)
         {
          c[rt].rs=0;
          c[rt].ps=0;
          c[rt].ls=1;
         }
         else
         {
             c[rt].rs=1;
             c[rt].ls=1;
             c[rt].ps=1;
         }
    return;
     }
    int mid=(l+r)/2;
    build(rt*2,l,mid);
    build(rt*2+1,mid+1,r);
    c[rt]=merge(c[rt*2],c[rt*2+1]);
}
void update(int rt,int l,int r,int x,int sign)
{
    if (l==r)
    {
        if (sign==1)
         {
          c[rt].rs=1;
          c[rt].ps=0;
          c[rt].ls=0;
         }
         else if (sign==0)
         {
          c[rt].rs=0;
          c[rt].ps=0;
          c[rt].ls=1;
         }
         else
         {
             c[rt].rs=1;
             c[rt].ls=1;
             c[rt].ps=1;
         }
         return;
    }
    int mid=(l+r)/2;
     if (x<=mid) update(rt*2,l,mid,x,sign);
     else update(rt*2+1,mid+1,r,x,sign);
    c[rt]=merge(c[rt*2],c[rt*2+1]);
}
Messi query(int rt,int l,int r,int L,int R)
{
   if (l>=L&&r<=R)
   {
       return c[rt];
   }
   int mid=(l+r)/2;
    if (R<=mid) return query(rt*2,l,mid,L,R);
    if (L>mid) return query(rt*2+1,mid+1,r,L,R);
   return merge(query(rt*2,l,mid,L,R),query(rt*2+1,mid+1,r,L,R));
}
int main()
{int i,j,k,x,y;
char ch;
    cin>>n>>m;
    build(1,1,n);
     for (i=1;i<=m;i++)
     {
         scanf("%d",&k);
          if (k==2)
          {
              scanf("%d%d",&x,&y);
              //cout<<‘p‘<<x<<‘ ‘<<y<<endl;
              printf("%d\n",query(1,1,n,x,y).sum);
         }
         else
         {
             int sign;
             scanf("%d %c",&x,&ch);
             //cout<<‘q‘<<x<<‘ ‘<<ch<<endl;
              if (ch==‘(‘)
                sign=1;
                else if (ch==‘)‘)sign=0;
                else sign=2;
              update(1,1,n,x,sign);
         }
     }
}
时间: 2024-08-08 01:13:24

妖梦斩木棒的相关文章

洛谷P3797 妖梦斩木棒

P3797 妖梦斩木棒 题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看做由三种小段构成,中间的n-2段都是左右都被切断的断头,我们记做’X’,最左边的一段和最右边的一段各有一个圆头,记做’(‘和’)’.幽幽子吃饱后闲来无事,决定戏弄一下妖梦.她拿来了许多这样的三种小段木棒,来替换掉妖梦切下来的n段中的一部分,然后问妖梦一些问题.这些操作可以这样描述: 1 x C 将第

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

妖梦斩木棒 思路: 略坑爹: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 200005 #define maxm maxn<<2 int n,m,L[maxm],R[maxm],mid[maxm],dis[maxm]; bool xx[maxm],ll[maxm],rr[maxm]; struct AnsType { int dis; bool l,r,x; }; inline void in(int

洛谷 P3797 妖梦斩木棒

妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看做由三种小段构成,中间的n-2段都是左右都被切断的断头,我们记做’X’,最左边的一段和最右边的一段各有一个圆头,记做’(‘和’)’.幽幽子吃饱后闲来无事,决定戏弄一下妖梦.她拿来了许多这样的三种小段木棒,来替换掉妖梦切下来的n段中的一部分,然后问妖梦一些问题.这些操作可以这样描述: 1 x C 将第x个小段的木棒替换成C型,C只会是

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

题目背景 妖梦是住在白玉楼的半人半灵,拥有使用剑术程度的能力. 题目描述 有一天,妖梦正在练习剑术.地面上摆放了一支非常长的木棒,妖梦把它们切成了等长的n段.现在这个木棒可以看做由三种小段构成,中间的n-2段都是左右都被切断的断头,我们记做’X’,最左边的一段和最右边的一段各有一个圆头,记做’(‘和’)’.幽幽子吃饱后闲来无事,决定戏弄一下妖梦.她拿来了许多这样的三种小段木棒,来替换掉妖梦切下来的n段中的一部分,然后问妖梦一些问题.这些操作可以这样描述: 1 x C 将第x个小段的木棒替换成C型

luoguP3799 妖梦拼木棒 [组合数学]

题目背景 上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来. 题目描述 有n根木棒,现在从中选4根,想要组成一个正三角形,问有几种选法? 输入输出格式 输入格式: 第一行一个整数n 第二行n个整数,a1,a2,……an(0<ai<=5000),代表每根木棒的长度. 输出格式: 一行一个整数,对1e9+7取模 输入输出样例 输入样例#1: 4 1 1 2 2 输出样例#1: 1 说明 对于30%的数据 N<=5000 对于100%的数据 N<=100000 木棍长度可以用桶存储

洛谷P3799 妖梦拼木棒

题目背景 上道题中,妖梦斩了一地的木棒,现在她想要将木棒拼起来. 题目描述 有n根木棒,现在从中选4根,想要组成一个正三角形,问有几种选法? 输入输出格式 输入格式: 第一行一个整数n 第二行n个整数,a1,a2,……an(0<ai<=5000),代表每根木棒的长度. 输出格式: 一行一个整数,对1e9+7取模 输入输出样例 输入样例#1: 复制 4 1 1 2 2 输出样例#1: 复制 1 说明 对于30%的数据 N<=5000 对于100%的数据 N<=100000 by-sz

luogu P3799 妖梦拼木棒

二次联通门 : luogu P3799 妖梦拼木棒 /* luogu P3799 妖梦拼木棒 用一个桶存下所有的木棒 美剧两根短的木棒长度 后随便乘一乘就 好了.. */ #include <algorithm> #include <cstdio> #define Mod 1000000007 #define Max 5000 void read (int &now) { now = 0; register char word = getchar (); while (wo

让妖梦酱抓狂的澈夕雅——花妖之章4

剧本完成之后就可以写代码了 using System;using System.Collections;using System.Collections.Generic;using UnityEngine; namespace Saruka.Character.Restina{ /// <summary> /// 蕾丝缇娜,第一关boss /// </summary> public class RestinaRosedoll : Boss { /// <summary>

让妖梦酱抓狂的澈夕雅——花妖之章1

今天我们来谈论一下如何给boss加难度 1.数值上调,这是最简单粗暴的一种难度增加的方法,也是最不负责的一种难度增加的方法,一般情况下,若策划能力不高或者是实在没有别的难度增加方法可以用这种方法.比如奥丁领域的hell难度就属于将玩家的血量控制在极低的数值来将容错降为0,但是这种方法容易降低玩家的体验,因为数值本身是存在一个合理的值的,随便调节数据会影响游戏的平衡,比如像奥丁领域的做法就废掉所有的防御装备,只让玩家使用进攻装备,一些以易伤换取伤害的装备的易伤也因此形同虚设. 2.技能躲避难度上调