• UVA 11996 Jewel Magic


    UVA_11996
        这个题目前三个操作都是典型的splay的操作,但是第四个操作之前没见过,我以前只用字典树+二分求过任意两个串的LCP,但这次是在splay上便一时间无从下手。后来看了别人的代码发现也是基于二分的,而至于如何判断二分出来的前缀是相同的,则直接用哈希值去比较了。

        至于直接用哈希值判断两个字符串是否相等,我一开始也觉得很不靠谱,后来分析了一下发现虽然不靠谱但不靠谱的概率是比较小的。假定我们用一个long long的哈希值,它可以区分出2^64个不同的字符串(当然这只是极限情况,如果哈希算法不同所能表示的字符串的数量也不大相同),而题目的01串至多也就400,000位,这样即便每个子串都不同也就才有1.6*10^11个,是远远小于2^64的,因此不同的子串出现同一个哈希值的概率微乎其微。

        为了让同样的字符串能得到同样的哈希值,可以用对应位的值乘以x的对应次幂来计算哈希值,x选3、选7都能AC,至于选别的我没试过,但是一定别选2之类的,因为用long long存x的幂相当于自动mod2^64,这样后面的值就都是0了……在维护splay的同时维护好当前节点所表示的区间的哈希值就可以了,由于涉及到翻转的操作,可以选择维护两个哈希值,一个是正着算的,一个是倒着算的,当一个区间翻转时只要将这两个哈希值交换就可以了,而不必再重新计算。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define MAXD 400010
    typedef long long LL;
    int N, M, T, node;
    LL fac[MAXD];
    struct Splay
    {
        int pre, ls, rs, key, size, rev;
        LL h[2];
        void pushdown(); void update(); void zig(int x); void zag(int x); void splay(int x, int goal);
        void init()
        {
            pre = ls = rs = key = size = rev = h[0] = h[1] = 0;    
        }
    }sp[MAXD];
    inline void Rev(int cur)
    {
        if(cur) sp[cur].rev ^= 1, std::swap(sp[cur].h[0], sp[cur].h[1]);
    }
    inline void Splay::pushdown()
    {
        if(rev)
        {
            Rev(ls), Rev(rs);
            std::swap(ls, rs);
            rev = 0;
        }
    }
    inline void Splay::update()
    {
        size = sp[ls].size + sp[rs].size + 1;
        h[0] = sp[ls].h[0] * fac[sp[rs].size + 1] + key * fac[sp[rs].size] + sp[rs].h[0];
        h[1] = sp[rs].h[1] * fac[sp[ls].size + 1] + key * fac[sp[ls].size] + sp[ls].h[1];
    }
    void Splay::zig(int x)
    {
        int y = rs, fa = pre;
        rs = sp[y].ls, sp[rs].pre = x;
        sp[y].ls = x, pre = y;
        sp[y].pre = fa;
        if(fa == 0) T = y;
        else sp[fa].rs == x ? sp[fa].rs = y : sp[fa].ls = y;
        update();
    }
    void Splay::zag(int x)
    {
        int y = ls, fa = pre;
        ls = sp[y].rs, sp[ls].pre = x;
        sp[y].rs = x, pre = y;
        sp[y].pre = fa;
        if(fa == 0) T = y;
        else sp[fa].rs == x ? sp[fa].rs = y : sp[fa].ls = y;
        update();
    }
    void Splay::splay(int x, int goal)
    {
        int y, z;
        for(; pre != goal;)
        {
            y = pre;
            if(sp[y].pre == goal) sp[y].rs == x ? sp[y].zig(y) : sp[y].zag(y);
            else
            {
                z = sp[y].pre;
                if(sp[z].rs == y)
                {
                    if(sp[y].rs == x) sp[z].zig(z), sp[y].zig(y);
                    else sp[y].zag(y), sp[z].zig(z);    
                }
                else
                {
                    if(sp[y].ls == x) sp[z].zag(z), sp[y].zag(y);
                    else sp[y].zig(y), sp[z].zag(z);
                }    
            }
        }
        update();
    }
    void Goto(int k, int goal)
    {
        int i = T, n;
        for(;;)
        {
            sp[i].pushdown();
            n = sp[sp[i].ls].size;
            if(n + 1 == k)
                break;
            else if(k <= n) i = sp[i].ls;
            else i = sp[i].rs, k -= n + 1;
        }
        sp[i].splay(i, goal);
    }
    char b[MAXD];
    void build(int &cur, int x, int y, int fa)
    {
        int mid = x + y >> 1;
        sp[mid].init();
        cur = mid, sp[mid].pre = fa, sp[mid].key = b[mid] - '0';
        if(x < mid) build(sp[mid].ls, x, mid - 1, mid);
        if(mid < y) build(sp[mid].rs, mid + 1, y, mid);
        sp[mid].update();
    }
    void init()
    {
        scanf("%s", b + 1);
        sp[0].init(), sp[N + 1].init(), sp[N + 2].init();
        T = N + 1, sp[N + 1].rs = N + 2, sp[N + 2].pre = N + 1;
        build(sp[N + 2].ls, 1, N, N + 2);
        sp[N + 2].update(), sp[N + 1].update();
        node = N + 2;
    }
    void newnode(int &cur, int c)
    {
        cur = ++ node;
        sp[cur].init(), sp[cur].key = c;
        sp[cur].update();
    }
    void insert(int x, int c)
    {
        Goto(x + 1, 0), Goto(x + 2, T);
        int cur = sp[T].rs;
        newnode(sp[cur].ls, c);
        sp[node].pre = cur;
        sp[cur].update(), sp[T].update();
    }
    void remove(int x)
    {
        Goto(x, 0), Goto(x + 2, T);
        int cur = sp[T].rs;
        sp[cur].ls = 0;
        sp[cur].update(), sp[T].update();    
    }
    void reverse(int x, int y)
    {
        Goto(x, 0), Goto(y + 2, T);
        Rev(sp[sp[T].rs].ls);
    }
    int hash(int x, int y)
    {
        Goto(x, 0), Goto(y + 2, T);
        return sp[sp[sp[T].rs].ls].h[0];
    }
    int common(int x, int y, int L)
    {
        return hash(x, x + L - 1) == hash(y, y + L - 1);
    }
    void LCP(int x, int y)
    {
        int min, mid, max, L = sp[T].size - 2;
        min = 0, max = std::min(L - x + 1, L - y + 1) + 1;
        for(;;)
        {
            mid = min + max >> 1;
            if(mid == min) break;
            if(common(x, y, mid)) min = mid;
            else max = mid;    
        }
        printf("%d\n", mid);
    }
    void solve()
    {
        int i, op, x, y;
        for(i = 0; i < M; i ++)
        {
            scanf("%d", &op);
            if(op == 1)
            {
                scanf("%d%d", &x, &y);
                insert(x, y);
            }
            else if(op == 2)
            {
                scanf("%d", &x);
                remove(x);
            }
            else if(op == 3)
            {
                scanf("%d%d", &x, &y);
                reverse(x, y);
            }
            else
            {
                scanf("%d%d", &x, &y);
                LCP(x, y);
            }
        }
    }
    int main()
    {
        fac[0] = 1;
        for(int i = 1; i < MAXD; i ++) fac[i] = 7 * fac[i - 1]; // Choosing 7 is just as my like.
        while(scanf("%d%d", &N, &M) == 2)
        {
            init();
            solve();    
        }
        return 0;    
    }
  • 相关阅读:
    【Python爬虫学习笔记10】多线程中的生产者消费者模式
    【Python爬虫学习笔记9】threading多线程
    【Python爬虫学习笔记8-2】MongoDB数据库操作详解
    【Python爬虫学习笔记8-1】MySQL数据库和MongoDB数据库存储概述
    【Python爬虫学习笔记7】CSV文件存储
    好书一起读(85):算法笔记
    好书一起读(82):电脑的原理
    写个shell脚本
    Scala基础语法
    初识函数式编程的一点漫谈
  • 原文地址:https://www.cnblogs.com/staginner/p/2654023.html
Copyright © 2020-2023  润新知