zoukankan      html  css  js  c++  java
  • BZOJ 1014 JSOI2008 火星人prefix Splay+Hash+二分

    题目大意:给定一个字符串。提供下列操作:

    1.查询从x開始的后缀和从y開始的后缀的最长公共前缀长度

    2.将x位置的字符改动为y

    3.在x位置的字符后面插入字符y

    看到这题一開始我先懵住了。

    。这啥。

    。我第一时间想到的是后缀数据结构 可是不会写 并且后缀数据结构也不支持改动操作

    后来无奈找了题解才知道是Hash+二分。。

    。 太强大了 Hash+二分打爆一切啊

    用Splay维护这个字符串的改动和插入操作 每一个节点维护子串的Hash值 推断时二分找到最长公共前缀

    只是这道题另一些注意事项

    1.此题不卡Hash 不会出现ABBABAABBAABABBA之类恶心字符串

    2.题目没有明说 可是字符串上全部字符都是小写字母

    3.二分时注意上界的取值 不能超过字符串长度 此题不保证x<y 一定要特判 否则就会RE

    剩下就非常裸了、、、80%达成 能够补个番了0.0

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define M 100100
    using namespace std;
    typedef unsigned long long ll;
    struct abcd{
    	abcd *fa,*ls,*rs;
    	int num,siz;ll hash;
    	abcd(int x);
    	void Push_Up();
    }*null=new abcd(0),*root=null;
    abcd :: abcd(int x)
    {
    	fa=ls=rs=null;
    	num=x;siz=x?

    1:0;hash=x; } ll ksm[M]; void abcd :: Push_Up() { siz=ls->siz+rs->siz+1; hash=ls->hash*ksm[rs->siz+1]+num*ksm[rs->siz]+rs->hash; } void Zig(abcd *x) { abcd *y=x->fa; y->ls=x->rs; x->rs->fa=y; x->rs=y; x->fa=y->fa; if(y==y->fa->ls) y->fa->ls=x; else if(y==y->fa->rs) y->fa->rs=x; y->fa=x; y->Push_Up(); if(y==root) root=x; } void Zag(abcd *x) { abcd *y=x->fa; y->rs=x->ls; x->ls->fa=y; x->ls=y; x->fa=y->fa; if(y==y->fa->ls) y->fa->ls=x; else if(y==y->fa->rs) y->fa->rs=x; y->fa=x; y->Push_Up(); if(y==root) root=x; } void Splay(abcd *x,abcd *Tar) { while(1) { abcd *y=x->fa,*z=y->fa; if(y==Tar) break; if(z==Tar) { if(x==y->ls) Zig(x); else Zag(x); break; } if(x==y->ls) { if(y==z->ls) Zig(y); Zig(x); } else { if(y==z->rs) Zag(y); Zag(x); } } x->Push_Up(); } void Find(abcd *x,int y,abcd *z) { while(1) { if(y<=x->ls->siz) x=x->ls; else { y-=x->ls->siz; if(y==1) break; y--; x=x->rs; } } Splay(x,z); } char s[M]; void Build_Tree(abcd *&x,int l,int r) { if(l>r) return ; int mid=l+r>>1; x=new abcd(s[mid]-'a'+1); Build_Tree(x->ls,l,mid-1); Build_Tree(x->rs,mid+1,r); x->ls->fa=x; x->rs->fa=x; x->Push_Up(); } void Initialize() { int i; ksm[0]=1; for(i=1;i<=100010;i++) ksm[i]=ksm[i-1]*31; scanf("%s",s); root=new abcd(19980402); root->rs=new abcd(19980402); Build_Tree(root->rs->ls,0,strlen(s)-1); root->rs->ls->fa=root->rs; root->rs->fa=root; root->rs->Push_Up(); root->Push_Up(); } bool Judge(int x,int y,int ans) { Find(root,x,null); Find(root,x+ans+1,root); ll hash1=root->rs->ls->hash; Find(root,y,null); Find(root,y+ans+1,root); ll hash2=root->rs->ls->hash; return hash1==hash2; } int Query(int x,int y) { int l=0,r=root->siz-2-max(x,y)+1; while(l+1<r) { int mid=l+r>>1; if( Judge(x,y,mid) ) l=mid; else r=mid; } if( Judge(x,y,r) ) return r; return l; } int m; int main() { int i,x,y; char p[10]; Initialize(); cin>>m; for(i=1;i<=m;i++) { scanf("%s",p); if(p[0]=='R') { scanf("%d%s",&x,p); Find(root,x+1,null); root->num=p[0]-'a'+1; root->Push_Up(); } else if(p[0]=='I') { scanf("%d%s",&x,p); Find(root,x+1,null); Find(root,x+2,root); root->rs->ls=new abcd(p[0]-'a'+1); root->rs->ls->fa=root->rs; root->rs->Push_Up(); root->Push_Up(); } else scanf("%d%d",&x,&y),printf("%d ", Query(x,y) ); } }




  • 相关阅读:
    intellij idea 将taskRequest.java文件识别为文本文档
    react 学习笔记2
    react 学习笔记1
    webpack4 配置笔记(转自掘金)
    音乐播放之进度条-自定义
    EBS
    Python 学习笔记
    Form 电子表格(JTF GRID)
    Form 中实现历史记录查询
    Form 去掉使用格式掩码带来的多余字符
  • 原文地址:https://www.cnblogs.com/wgwyanfs/p/7387790.html
Copyright © 2011-2022 走看看