首页 > 其他分享 >题解:UVA11996 Jewel Magic

题解:UVA11996 Jewel Magic

时间:2024-08-25 21:07:17浏览次数:6  
标签:node siz Magic lc int 题解 UVA11996 rc rt

题意

给你一个 01 串,要求完成以下操作:

  • 单点插入。

  • 单点删除。

  • 区间翻转。

  • 查询两点开始的 LCP。

分析

先看查询操作,如何得到 LCP 的长度?

我们可以考虑二分长度 \(l\),然后用哈希检验区间 \([p1, p1+l-1]\) 是否等于区间 \([p2, p2+l-1]\)。

平衡树维护哈希即可。


发现还有一个翻转操作,这时又应当如何操作?

考虑多存一个哈希记录翻转后的哈希值。

翻转操作时交换正反哈希。

Code

发一份指针版 FHQ Treap。

#include<bits/stdc++.h>
using namespace std;
#define lx 114
typedef uint64_t hash_t;
#define maxn 400005

hash_t lev[maxn];

struct Treap
{
    #define siz(x) (x?x->siz:0)
    #define hsh(x) (x?x->hsh:0)
    #define rhsh(x) (x?x->rhsh:0)

    mt19937 rnd;

    Treap(uint32_t s=114) { rnd.seed(s); }

    struct node
    {
        node *lc, *rc;
        uint32_t siz, id;
        uint8_t ch;
        hash_t hsh, rhsh;
        uint8_t rev;
        node(uint8_t c, uint32_t i)
        {
            id=i;
            lc=rc=nullptr;
            siz=1, hsh=rhsh=ch=c;
            rev=0;
        }

        node *push_up()
        {
            siz=siz(lc)+siz(rc)+1;
            hsh=lev[siz(rc)+1]*hsh(lc)+lev[siz(rc)]*ch+hsh(rc);
            rhsh=lev[siz(lc)+1]*rhsh(rc)+lev[siz(lc)]*ch+rhsh(lc);
            return this;
        }

        void reverse()
        {
            swap(hsh, rhsh);
            swap(lc, rc);
            rev^=1;
        }

        void push_down()
        {
            if(!rev) return;
            if(lc) lc->reverse();
            if(rc) rc->reverse();
            rev^=1;
        }
    };

    node *rt;

    node *new_node(uint8_t c) { return new node(c, rnd()); }

    void split(node *x, uint32_t k, node *&l, node *&r)
    {
        if(!x) return l=r=0, void();
        x->push_down();
        if(siz(x->lc)<k) l=x, split(x->rc, k-siz(x->lc)-1, x->rc, r);
        else             r=x, split(x->lc, k, l, x->lc);
        x->push_up();
    }

    node *merge(node *x, node *y)
    {
        if(!x||!y) return x?x:y;
        if(x->id<y->id)
        {
            x->push_down();
            x->rc=merge(x->rc, y);
            return x->push_up();
        }
        else
        {
            y->push_down();
            y->lc=merge(x, y->lc);
            return y->push_up();
        }
    }

    void push_back(uint8_t c) { rt=merge(rt, new_node(c)); }

    void insert(int p, uint8_t c)
    {
        node *a, *b;
        split(rt, p, a, b);
        rt=merge(a, merge(new_node(c), b));
    }

    void erase(int p)
    {
        node *a, *b, *c;
        split(rt, p-1, a, b);
        split(b, 1, b, c);
        rt=merge(a, c);
    }

    void reverse(int l, int r)
    {
        node *a, *b, *c;
        split(rt, l-1, a, b);
        split(b, r-l+1, b, c);
        b->reverse();
        rt=merge(merge(a, b), c);
    }

    hash_t query(int l, int r)
    {
        node *a, *b, *c;
        split(rt, l-1, a, b);
        split(b, r-l+1, b, c);
        hash_t ret=b->hsh;
        rt=merge(merge(a, b), c);
        return ret;
    }
}tr(114514);

string s;

bool chk(int p1, int p2, int l, int mxlen)
{
    if(p1+l-1>mxlen||p2+l-1>mxlen) return 0;
    hash_t h1=tr.query(p1, p1+l-1);
    hash_t h2=tr.query(p2, p2+l-1);
    return h1==h2;
}

int LCP(int p1, int p2)
{
    if(!tr.rt) return 0;
    int len=tr.rt->siz;
    int ret=0;
    for(int i=1<<20;i;i>>=1)
        if(chk(p1, p2, ret+i, len)) ret+=i;
    return ret;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    lev[0]=1;
    for(int i=1;i<maxn;i++) lev[i]=lev[i-1]*lx;
    int m;
    cin>>m>>m;
    cin>>s;
    for(auto c:s) tr.push_back(c);
    while(m--)
    {
        int op, p, x;
        cin>>op>>p;
        if(op==1) cin>>x, tr.insert(p, x^48);
        if(op==2) tr.erase(p);
        if(op==3) cin>>x, tr.reverse(p, x);
        if(op==4) cin>>x, cout<<LCP(p, x)<<'\n';
    }
}

标签:node,siz,Magic,lc,int,题解,UVA11996,rc,rt
From: https://www.cnblogs.com/redacted-area/p/18379552

相关文章

  • 题解:AT_abc354_g [ABC354G] Select Strings
    题目分析题意给定\(n\)个字符串,要求从中选出若干个组成一个集合,且集合中每个字符串都互不包含。求集合中字符串的权值的和的最大值。分析首先很容易想到用KMP判两个串是否存在包含关系。考虑建图,将不能同时存在于一个集合中的串的节点相连。然后发现只需求出这个图的最......
  • 题解:P7952 [✗✓OI R1] 天动万象
    提供一种和第一篇题解不同的理解思路。题目分析看到操作\(1\):拿dfs序水水就行了。看到操作\(2\):???特殊情况我们考虑一下特殊情况下操作\(2\)怎么处理。假如这棵树是一条链。设从根到叶节点权值如下:(随便赋的)节点编号123456权值123456如果我们......
  • 题解:CF1995C Squaring
    题意给定序列\(a\),每次操作可以使\(a_i\getsa_i^2\),求使\(a\)不降的最少操作次数。分析因为\(1^k=1\),所以无解的情况只有\(\exist\a_i=1\)且\(\exist\j\in[1,i),a_j>1\)。在有解的情况下,假设对\(a_{i-1}\)操作\({k_{i-1}}\)次,对\(a_i\)操作\({k_i}\)次。......
  • 题解:UVA1479 Graph and Queries
    分析先看删边操作。由于并不保证是森林,所以我们没有好的方法来在线维护删边相关的操作。所以,我们可以套路地把询问离线,然后倒着操作。删边变成加边。需要注意的是权值的修改,记录时要把当前权值和修改的权值反过来。然后我们发现这个操作很经典,维护方式和[HNOI2012]永无乡......
  • 题解:P7475 「C.E.L.U-02」简易输入法
    题意给定词典\(\text{U}\),每次询问读入一个字符串\(s\),以及一个整数\(x\)对于这个字符串有以下几种情形:设\(s_i\in\text{U}\)且\(s\)为\(s_i\)的前缀的个数为\(a\)。当\(a\gex\)时,请输出按照以输出次数从大到小为第一关键字,以字典序为第二关键字排序后的第\(x......
  • 题解:P7401 [COCI2020-2021#5] Planine
    题意现有一座上下起伏的山。它可以抽象为一个包含\(n\)(\(n\)为奇数)个点\((x_i,y_i)\)以及\((x_1,-\inf)\)与\((x_n,-\inf)\)的多边形。对于所有满足\(i\neq1\),\(i\neqn\),\(i\bmod2=1\)的整数\(i\),\((x_i,y_i)\)都是山谷。现要放置若干个高度为\(h\)的点光......
  • 题解:SP1182 SORTBIT - Sorted bit squence
    题意将区间\([m,n]\)的所有整数按照其二进制位表示的数中\(1\)的数量从小到大排序。如果\(1\)的数量相同,则按照数的大小排序。求序列中第\(k\)个数。其中,负数使用补码来表示:一个负数的二进制数与其相反数的二进制数之和恰好等于\(2^{32}\)。分析考虑用uint32_t存......
  • 题解:P3266 [JLOI2015] 骗我呢
    题意有一个\(n\timesm\)的数组\(x_{i,j}(1\lei\len,1\lej\lem)\),满足:\(x_{i,j}\in[0,m]\)\(\foralli\in[1,n],\forallj\in[1,m),x_{i,j}<x_{i,j+1}\)\(\foralli\in(1,n],\forallj\in[1,m),x_{i,j}<x_{i-1,j+1}\)......
  • 题解:CF70D Professor's task
    题意实现以下两种操作:往点集\(S\)中添加一个点\((x,y)\)。询问点\((x,y)\)是否在点集\(S\)的凸包中。分析动态凸包板子。建议先完成P2521[HAOI2011]防线修建。上题维护的是上半个凸包,本题维护上下两个。将凸包中的点按\(x\)排序,通过\((x,y)\)前驱......
  • 题解:P2521 [HAOI2011] 防线修建
    题意给定若干个点,实现下列操作:删除一个点。查询上凸包的周长。分析建议先完成【模板】二维凸包。对于这个删除操作,我们没有好的方法去在线维护它。考虑离线询问。这样删除操作就变成了插入操作。插入一个新点有如下两种情况:新点在凸包内。新点在凸包外。我们回忆......