• bzoj 1014: 洛谷 P4036: [JSOI2008]火星人


    题目传送门:洛谷P4036

    题意简述:

    有一个字符串,支持插入字符,修改字符。

    每次需要查询两个后缀的LCP长度。

    最终字符串长度(le 100,!000),修改和询问的总个数(le 150,!000),查询操作(le 10,!000)。

    题解:

    由后缀和LCP可以想到后缀数组或后缀自动机,但是它们都无法插入或修改。

    考虑到LCP可以通过二分+哈希的方式来计算,考虑维护区间的哈希值。

    这里使用平衡树无旋Treap来维护区间的哈希值。

    一次修改(O(log n)),一次询问(O(log^2 n))。

    bzoj时限略卡,用了自然溢出才过。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define Bse 19260817u
      4 unsigned Pow[100005];
      5 
      6 char Str[100005];
      7 int N,Q;
      8 int ls[100005],rs[100005],siz[100005],pri[100005],val[100005],cnt,Root;
      9 unsigned ha[100005];
     10 
     11 unsigned ran(){static unsigned x=23333;return x^=x<<13,x^=x>>17,x^=x<<5;}
     12 
     13 void combine(int id){
     14     siz[id]=siz[ls[id]]+1+siz[rs[id]];
     15     ha[id]=Pow[siz[rs[id]]+1]*ha[ls[id]]+Pow[siz[rs[id]]]*val[id]+ha[rs[id]];
     16 }
     17 
     18 int Merge(int rt1,int rt2){
     19     if(!rt1) return rt2;
     20     if(!rt2) return rt1;
     21     if(pri[rt1]>=pri[rt2]){
     22         rs[rt1]=Merge(rs[rt1],rt2);
     23         combine(rt1);
     24         return rt1;
     25     }
     26     else{
     27         ls[rt2]=Merge(rt1,ls[rt2]);
     28         combine(rt2);
     29         return rt2;
     30     }
     31 }
     32 
     33 void Split(int rt,int k,int&rt1,int&rt2){
     34     if(!rt) {rt1=rt2=0; return;}
     35     if(k<=siz[ls[rt]]){
     36         Split(ls[rt],k,rt1,rt2);
     37         ls[rt]=rt2;
     38         combine(rt);
     39         rt2=rt;
     40     }
     41     else{
     42         Split(rs[rt],k-siz[ls[rt]]-1,rt1,rt2);
     43         rs[rt]=rt1;
     44         combine(rt);
     45         rt1=rt;
     46     }
     47 }
     48 
     49 void Insert(int pos,int v){
     50     val[++cnt]=v, ha[cnt]=v, pri[cnt]=ran(), siz[cnt]=1;
     51     int rt1,rt2;
     52     Split(Root,pos,rt1,rt2);
     53     Root=Merge(Merge(rt1,cnt),rt2);
     54 }
     55 
     56 void Change(int pos,int v){
     57     int rt1,rt2,rt3,rt4;
     58     Split(Root,pos-1,rt1,rt2);
     59     Split(rt2,1,rt3,rt4);
     60     val[rt3]=v; combine(rt3);
     61     Root=Merge(Merge(rt1,rt3),rt4);
     62 }
     63 
     64 unsigned chk(int pos,int len){
     65     int rt1,rt2,rt3,rt4;
     66     Split(Root,pos-1,rt1,rt2);
     67     Split(rt2,len,rt3,rt4);
     68     unsigned D=ha[rt3];
     69     Root=Merge(Merge(rt1,rt3),rt4);
     70     return D;
     71 }
     72 
     73 int main(){
     74     Pow[0]=1; for(int i=1;i<=100000;++i) Pow[i]=Pow[i-1]*Bse;
     75     scanf("%s",Str+1);
     76     N=strlen(Str+1);
     77     for(int i=1;i<=N;++i)
     78         Insert(i-1,Str[i]);
     79     scanf("%d",&Q);
     80     for(int i=1;i<=Q;++i){
     81         int x,y; char opt[5];
     82         scanf("%s",opt);
     83         if(*opt=='Q'){
     84             scanf("%d%d",&x,&y);
     85             int l=1, r=N-max(x,y)+1, mid, ans=0;
     86             while(l<=r){
     87                 mid=l+r>>1;
     88                 if(chk(x,mid)==chk(y,mid)) ans=mid, l=mid+1;
     89                 else r=mid-1;
     90             }
     91             printf("%d
    ",ans);
     92         }
     93         else if(*opt=='R'){
     94             scanf("%d%s",&x,opt);
     95             Change(x,*opt);
     96         }
     97         else if(*opt=='I'){
     98             scanf("%d%s",&x,opt);
     99             Insert(x,*opt);
    100             ++N;
    101         }
    102     }
    103     return 0;
    104 }
    105 
    106 // luogu P4036 - Fhq-Treap + hash. 18:20 ~ 19:03
  • 相关阅读:
    jquery 绑定事件前先解除事件绑定
    jquer ajax的方法返回值
    jQuery动态生成不规则表格前后端
    常见的正则表达式
    锚点连接
    javascript动态添加删除表格
    java面试题之第二回
    [转]java抽象类和接口
    Java IO 和 NIO
    Java IO之序列化
  • 原文地址:https://www.cnblogs.com/PinkRabbit/p/9581990.html
Copyright © 2020-2023  润新知