UVA 11996 Jewel Magic(伸展树+字符串hash)

大白书例题。

4种操作,插入操作可以像普通的排序二叉树那样插入,也可以利用2次伸展操作把第k-1个伸展到根节点,以及把根节点的右子树中的第一个伸展到根节点右子树节点,再把要插入的节点插入到右子树的左子树。

删除操作也可以像刚才一样,先把第k-1个伸展到根,再把右子树中第2个伸展到右子树处,这样右子树的左子树就是要删除的节点。

反转操作是通过类似刚才的操作提取那一段,再把这一段的左右子树交换,正反哈希值交换,同时打上一个标记用于下传。

查询2个后缀的LCP也类似,提取那一段,查询哈希值。

具体实现在最前面后最后分别加了一个节点,目的是刚才那个操作可能会k-1是0,以及查询哈希值的时候可能到末尾,因而提取操作的第二步是要把末尾的后一个伸展到根节点的右子树上,所以最后加了一个节点以防出错。

有些代码注掉的也是对的,不过用了别的方法,功能是一样的,效率上有差别。

AC代码:

#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<string.h>
#include<string>
#include<sstream>
#include<bitset>
using namespace std;
#define ll long long
#define ull unsigned long long
#define eps 1e-8
#define NMAX 201000
#define MOD 1000000007
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1)
template<class T>
inline void scan_d(T &ret)
{
    char c;
    int flag = 0;
    ret=0;
    while(((c=getchar())<'0'||c>'9')&&c!='-');
    if(c == '-')
    {
        flag = 1;
        c = getchar();
    }
    while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
    if(flag) ret = -ret;
}
const int x = 137;
const int maxn = 200000+10;
ull X[maxn*2+10];
struct Node
{
    Node* ch[2];
    int num,s,flip;
    ull hashv,rehashv;
    int cmp(int x)
    {
        if(x == ch[0]->s+1) return -1;
        if(x < ch[0]->s+1) return 0;
        return 1;
    }
    void maintain()
    {
        s = ch[0]->s+ch[1]->s+1;
        hashv = ch[0]->hashv + (ull)num*X[ch[0]->s] + ch[1]->hashv*X[ch[0]->s+1];
        rehashv = ch[1]->rehashv + (ull)num*X[ch[1]->s] + ch[0]->rehashv*X[ch[1]->s+1];
    }
    void reverse()
    {
        swap(ch[0],ch[1]);
        swap(hashv,rehashv);
        flip ^= 1;
    }
    void pushdown()
    {
        if(flip)
        {
            flip = 0;
            ch[0]->reverse();
            ch[1]->reverse();
        }
    }
};
Node* null = new Node();

void node_init(Node* &o, int num)
{
    o->ch[0] = o->ch[1] = null;
    o->num = o->hashv = o->rehashv = num;
    o->s = 1;
    o->flip = 0;
}

void rotate(Node* &o, int d)
{
    Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;
    o->maintain(); k->maintain(); o = k;
}

void splay(Node* &o, int k)
{
    o->pushdown();
    int d = o->cmp(k);
    if(d == 1) k -= o->ch[0]->s+1;
    if(d != -1)
    {
        Node* p = o->ch[d];
        p->pushdown();
        int d2 = p->cmp(k);
        if(d2 == 1) k -= p->ch[0]->s+1;
        if(d2 != -1)
        {
            splay(p->ch[d2],k);
            if(d == d2) rotate(o,d^1);
            else rotate(o->ch[d],d);
        }
        rotate(o,d^1);
    }
}

void insert(Node* &o, int pos, int val)
{
    o->pushdown();
    int d = (pos <= o->ch[0]->s+1) ? 0 : 1;
    if(d == 1) pos -= o->ch[0]->s+1;
    if(o->ch[d] == null)
    {
        o->ch[d] = new Node();
        node_init(o->ch[d],val);
        o->maintain();
        return;
    }
    insert(o->ch[d],pos,val);
    o->maintain();
//    splay(o,pos-1);
//    splay(o->ch[1],1);
//    o->ch[1]->ch[0] = new Node();
//    node_init(o->ch[1]->ch[0],val);
//    o->ch[1]->maintain();
//    o->maintain();
}

void del(Node* &o, int pos)
{
    splay(o,pos);
    Node *left = o->ch[0], *right = o->ch[1];
    delete o;
    splay(left,left->s);
    left->ch[1] = right;
    o = left;
    o->maintain();
//    splay(o,pos-1);
//    splay(o->ch[1],2);
//    o->ch[1]->ch[0] = null;
//    o->ch[1]->maintain();
//    o->maintain();
}

//Node* merge(Node* left, Node* right)
//{
//    splay(left,left->s);
//    left->ch[1] = right;
//    left->maintain();
//    return left;
//}

//void split(Node* o, int k, Node* &left, Node* &right)
//{
//    splay(o,k);
//    left = o;
//    right = o->ch[1];
//    left->ch[1] = null;
//    left->maintain();
//}

void dfs(Node* &o)
{
    if(o != null)
    {
        o->pushdown();
        dfs(o->ch[0]);
        if(o->num != -1) printf("%d",o->num);
        dfs(o->ch[1]);
    }
}

char s[maxn];
void build(Node* &o, int n, int ge)
{
    int p = (n+1)/2;
    o = new Node();
    node_init(o,s[ge+p-1]-'0');
    if(p > 1) build(o->ch[0],p-1,ge);
    if(n-p >= 1) build(o->ch[1],n-p,ge+p);
    o->maintain();
}

void buildit(Node* &o, int n)
{
    o = new Node();
    node_init(o,-1);//最前面
    o->ch[1] = new Node();
    node_init(o->ch[1],-1);//最后面
    build(o->ch[1]->ch[0],n,0);
    o->ch[1]->maintain();
    o->maintain();
}

void removetree(Node* &o)
{
    if(o == NULL) return;
    removetree(o->ch[0]);
    removetree(o->ch[1]);
    delete o;
    o = NULL;
}

Node* root;

ull gethash(int x, int y)
{
    splay(root,x-1);
    splay(root->ch[1],y-x+2);
    root->ch[1]->maintain();
    root->maintain();
    return root->ch[1]->ch[0]->hashv;
}

int main()
{
#ifdef GLQ
    freopen("input.txt","r",stdin);
//    freopen("o3.txt","w",stdout);
#endif
    X[0] = 1;
    for(int i = 1; i <= maxn*2; i++)
        X[i] = X[i-1]*(ull)x;
    null->s = null->hashv = null->rehashv = 0;
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        scanf("%s",s);
//        if(root != NULL) removetree(root);
        buildit(root,n);
        while(m--)
        {
            int type,p1,p2;
            scanf("%d",&type);
            if(type == 1)
            {
                scanf("%d%d",&p1,&p2);
                insert(root,p1+2,p2);
//                dfs(root);
//                cout<<endl;
            }
            else if(type == 2)
            {
                scanf("%d",&p1);
                del(root,p1+1);
//                dfs(root);
//                cout<<endl;
            }
            else if(type == 3)
            {
                scanf("%d%d",&p1,&p2);
                p1++; p2++;
//                Node *left,*mid,*right,*o;
//                split(root,p1-1,left,o);
//                split(o,p2-p1+1,mid,right);
//                mid->reverse();
//                root = merge(merge(left,mid),right);
                splay(root,p1-1);
                splay(root->ch[1],p2-p1+2);
                root->ch[1]->ch[0]->reverse();
                root->ch[1]->maintain();
                root->maintain();
//                dfs(root);
//                cout<<endl;
            }
            else
            {
                scanf("%d%d",&p1,&p2);
                p1++; p2++;
                int l = 1,r = root->s-2-max(p1,p2)+2;
                int ans = 0;
                while(l <= r)
                {
                    int mid = (l+r)>>1;
                    if(gethash(p1,p1+mid-1) == gethash(p2,p2+mid-1))
                    {
                        ans = mid;
                        l = mid+1;
                    }
                    else r = mid-1;
                }
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值