• CF1340F Nastya and CBS


    原题链接

    定义(f(S)=去除所有括号珂以匹配的子串后的剩下的字符串),例如:(f())[]([)]([])[[())=)([)][[

    (S)中含有交错的括号序列,如([)],则称(S)为WBS(wrong brackets sequence)。

    如果字符串(S)是一个CBS(correct brackets sequence),则(f(S)=operatorname {null})

    否则,那么(f(S))必然会有一下3种情况:

    1. (f(S))是WBS

    2. (f(S))左侧有多余的右括号

    3. (f(S))右侧有多余的左括号

    我们考虑用线段树维护(f(S))

    先想想合并两个字符串(S_l,S_r)需要用到哪些东西

    首先要有一个玩意儿来判断(S)是否是WBS,因为两个WBS合并后也是一个WBS。然后就要处理左右括号的问题。

    只有(S_r)的左边的右括号有珂能和(S_l)的右边的右括号合并。这要满足(S_l)的右边的左括号和(S_r)的左边的右括号的括号类型是相同的。

    所以,我们维护线段树上的字符串(S),需要用到(3)个东西:

    1. 一个boolean值(判断(S)是否为WBS)

    2. 一个字符串(l),代表(S)左边的右括号

    3. 一个字符串(r),代表(S)右边的左括号

    直接维护(l,r)显然代价太大了,考虑用可持久化treap维护这两个玩意儿。

    因为我们要判断(S_l)右边的左括号和(S_r)左边的右括号是否匹配,所以我们还需要在可持久化treap上维护字符串的hash值。

    至于为什么要用可持久化treap,我来解释一下:

    1. (S_l)的右边的左括号的长度和(S_r)的左边的右括号的长度是不确定的,我们需要来裁剪一段最长的字符串来看是否匹配,如果匹配,还要把匹配的部分删掉,这是线段树所不能做的事情

    2. 如果你用的是treap而不是可持久化treap,在线段树父级节点删除匹配的部分的时候,子节点也会一起把那个删掉。所以要用可持久化treap克隆一下节点。

    贴一下代码:

    // Code by H~$~C
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <assert.h>
    #include <stdint.h>
    #include <stdbool.h>
    #include <time.h>
    #define lambda(return_type, function_body) ({ return_type $this function_body $this; })
    #define $ lambda // it won't allow comma (that is ',') without brackets in the function body!
    #define inline __attribute__((__always_inline__)) __inline
    #define eprintf(...) (fprintf(stderr, __VA_ARGS__) & fflush(stderr))
    #define max(a, b) ({ __typeof(a) _A = a, _B = b; (_A > _B) ? a : b; })
    #define min(a, b) ({ __typeof(a) _A = a, _B = b; (_A < _B) ? a : b; })
    #define swap(a, b) ({ __typeof(a) _swap_tmp = a; a = b; b = _swap_tmp; 0; })
    typedef long long int64;
    typedef unsigned long long hash_type;
    
    const hash_type BASE = 100003;
    const hash_type MOD = 1000000007;
    
    #define Maxn 100005
    
    int n, k, q;
    int a[Maxn];
    bool lb[Maxn];
    hash_type pw[Maxn];
    
    // treap
    #define T_Maxn 3000000
    #define T_RMaxn 2950000
    typedef struct {
      int size, fix;
      int l, r;
      int key;
      hash_type hash;
    } t_node;
    int total_node;
    #define ls tr[p].l
    #define rs tr[p].r
    t_node tr[T_Maxn];
    inline void t_clear() {
      total_node = 0;
      tr[0].size = tr[0].fix = 0;
      tr[0].l = tr[0].r = 0;
      tr[0].key = 0;
      tr[0].hash = 0;
    }
    inline void t_initialize(int p, int v) {
      tr[p].size = 1;
      tr[p].fix = ((rand() << 15) | rand());
      tr[p].l = tr[p].r = 0;
      tr[p].key = v;
      tr[p].hash = v;
    }
    #define t_newnode(...)                          
    ({                                              
      t_initialize(++total_node, __VA_ARGS__);      
      total_node;                                   
    })
    #define t_clone(p) ({ tr[++total_node] = tr[p]; total_node; })
    inline void t_pushup(int p) {
      if (!p) return ;
      tr[p].size = tr[ls].size + tr[rs].size + 1;
      tr[p].hash = (tr[ls].hash * pw[tr[rs].size + 1] + tr[p].key * pw[tr[rs].size] + tr[rs].hash) % MOD;
    }
    int t_merge(int l, int r) {
      if (!l || !r) return l | r;
      if (tr[l].fix < tr[r].fix) {
        l = t_clone(l);
        tr[l].r = t_merge(tr[l].r, r);
        t_pushup(l);
        return l;
      }
      else {
        r = t_clone(r);
        tr[r].l = t_merge(l, tr[r].l);
        t_pushup(r);
        return r;
      }
    }
    void t_split(int p, int s, int *l, int *r) {
      if (!p) *l = *r = 0;
      else {
        p = t_clone(p);
        int lsize = tr[ls].size + 1;
        if (lsize <= s) {
          *l = p;
          t_split(rs, s - lsize, &tr[*l].r, r);
          t_pushup(*l);
        }
        else {
          *r = p;
          t_split(ls, s, l, &tr[*r].l);
          t_pushup(*r);
        }
      }
    }
    #undef ls
    #undef rs
    
    bool usl[Maxn << 2];
    int lf[Maxn << 2], rf[Maxn << 2];
    #define ls (p << 1)
    #define rs ((p << 1) | 1)
    #define mid ((l + r) >> 1)
    void merge_answers(bool usl, bool usr, int l1, int r1, int l2, int r2, bool *us, int *l, int *r) {
      *us = usl || usr;
      if (*us) return ;
      int A, B;
      if (tr[r1].size >= tr[l2].size) {
        t_split(r1, tr[r1].size - tr[l2].size, &A, &B);
        if (tr[B].hash != tr[l2].hash) *us = 1;
        else {
          *us = 0;
          *l = l1;
          *r = t_merge(A, r2);
        }
      }
      else {
        t_split(l2, tr[l2].size - tr[r1].size, &A, &B);
        if (tr[B].hash != tr[r1].hash) *us = 1;
        else {
          *us = 0;
          *l = t_merge(A, l1);
          *r = r2;
        }
      }
    }
    inline void pushup(int p) {
      merge_answers(usl[ls], usl[rs], lf[ls], rf[ls], lf[rs], rf[rs], usl + p, lf + p, rf + p);
    }
    inline void apply(int p, int id) {
      lf[p] = rf[p] = usl[p] = 0;
      if (lb[id]) rf[p] = t_newnode(a[id]);
      else lf[p] = t_newnode(a[id]);
    }
    void build(int p, int l, int r) {
      if (l == r)
        return apply(p, l);
      build(ls, l, mid);
      build(rs, mid + 1, r);
      pushup(p);
    }
    void modify(int p, int l, int r, int pos, int v, bool dir) {
      if (l == r) {
        a[l] = v;
        lb[l] = dir;
        return apply(p, l);
      }
      if (pos <= mid)
        modify(ls, l, mid, pos, v, dir);
      else
        modify(rs, mid + 1, r, pos, v, dir);
      pushup(p);
    }
    bool query(int p, int l, int r, int L, int R, int *nlf, int *nrf) {
      if (L > r || l > R) {
        *nlf = *nrf = 0;
        return false;
      }
      if (L <= l && r <= R) {
        *nlf = lf[p];
        *nrf = rf[p];
        return usl[p];
      }
      int nlf1 = 0, nlf2 = 0, nrf1 = 0, nrf2 = 0;
      bool usl1 = query(ls, l, mid, L, R, &nlf1, &nrf1);
      bool usl2 = query(rs, mid + 1, r, L, R, &nlf2, &nrf2);
      bool usl0 = false;
      merge_answers(usl1, usl2, nlf1, nrf1, nlf2, nrf2, &usl0, nlf, nrf);
      return usl0;
    }
    
    int main() {
      srand(time(NULL));
      pw[0] = 1ULL;
      for (int i = 1; i < Maxn; ++i)
        pw[i] = pw[i - 1] * BASE % MOD;
      scanf("%d%d", &n, &k);
      for (int i = 1; i <= n; ++i) {
        scanf("%d", a + i);
        lb[i] = (a[i] > 0);
        if (a[i] < 0) a[i] = -a[i];
      }
      build(1, 1, n);
      scanf("%d", &q);
      while (q--) {
        int op;
        scanf("%d", &op);
        if (op == 1) {
          int x, v;
          scanf("%d%d", &x, &v);
          modify(1, 1, n, x, v > 0 ? v : -v, v > 0);
        }
        else {
          int l, r;
          scanf("%d%d", &l, &r);
          int nlf = 0, nrf = 0;
          bool ans = query(1, 1, n, l, r, &nlf, &nrf);
          puts((ans || nlf || nrf) ? "No" : "Yes");
        }
        if (total_node >= T_RMaxn) {
          total_node = 0;
          build(1, 1, n);
        }
      }
      return 0;
    }
    
    
  • 相关阅读:
    silverlight的Datagrid控件列绑定属性笔记
    VC字符串处理整理
    Combobox实现多项选择 Silverlight下“Combobox”怎样实现多项选择?
    C# 类初始化顺序
    Silverlight程序设置断点无法进入调试的解决方案
    有哪些适合新手练手的Python项目?
    Ubuntu 终端常用命令
    浅析python 中__name__ = '__main__' 的作用
    py thon 多线程(转一篇好文章)
    python os.path模块
  • 原文地址:https://www.cnblogs.com/libra9z/p/12795641.html
Copyright © 2020-2023  润新知