zoukankan      html  css  js  c++  java
  • [bzoj1014][JSOI2008]火星人prefix

      splay维护区间内的hash值+二分答案。。。

      一开始脑残跑去维护各个前缀的hash值。。结果发现修改的时候没法打懒标记(也可能是我太弱不会)

      跑去看黄学长题解发现直接维护区间内的hash值就可以了。。而且挺容易合并的TAT(其实挺显然的,都用splay了为啥还不维护区间的hash值。。。)

      然后就变水题了= =而且这题数据弱可以直接自然溢出。。。。当然就算这样我的splay还是一如既往的慢TAT

      每次查询的时候二分lcp长度就好了。

      时间复杂度O(nlog²n)。。。还有一个巨大的常数因子233

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #define ll unsigned long long
     5 using namespace std;
     6 const int maxn=100033;
     7 ll hash[maxn],jc[maxn];
     8 int ch[maxn][2],size[maxn],fa[maxn],num[maxn];
     9 int i,j,n,m,x,y,rt,tot;
    10 char s[maxn];
    11 int ra;char rx;
    12 inline int read(){
    13     rx=getchar();ra=0;
    14     while(rx<'0'||rx>'9')rx=getchar();
    15     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
    16 }
    17 inline void upd(int x){
    18     int l=ch[x][0],r=ch[x][1];
    19     size[x]=size[l]+1+size[r];
    20     hash[x]=hash[l]*jc[size[x]-size[l]]+num[x]*jc[size[r]]+hash[r];
    21 }
    22 inline void rotate(int x,int &rt){
    23     int f=fa[x],gfa=fa[f];
    24     if(f==rt)rt=x;else ch[gfa][ch[gfa][1]==f]=x;
    25     int l=ch[f][1]==x,r=l^1;
    26     fa[x]=gfa,fa[f]=x,ch[f][l]=ch[x][r],ch[x][r]=f,fa[ch[f][l]]=f;
    27     upd(f),upd(x);
    28 }
    29 void splay(int x,int &rt){
    30     int f,gfa;
    31     while(x!=rt){
    32         f=fa[x],gfa=fa[f];
    33         if(f!=rt)rotate(((ch[f][0]==x)^(ch[gfa][0]==f))?x:f,rt);
    34         rotate(x,rt);
    35     }
    36 }
    37 int find(int x,int k){
    38     int l=ch[x][0];
    39     if(size[l]>=k)return find(l,k);
    40     else if(size[l]+1==k)return x;
    41     else return find(ch[x][1],k-size[l]-1);
    42 }
    43 void change(int now,char c){
    44     int x=find(rt,now);splay(x,rt);
    45     int y=find(rt,now+1);splay(y,ch[x][1]);
    46     hash[y]+=(ll)(c-'a'+13-num[y])*jc[size[y]-1];
    47     num[y]=c-'a'+13,upd(x);
    48 }
    49 void ins(int now,char c){
    50     int x=find(rt,now+1);splay(x,rt);
    51     int y=find(rt,now+2),z;splay(y,ch[x][1]);
    52     ch[y][0]=z=++tot;num[z]=c-'a'+13,fa[z]=y,size[z]=1,hash[z]=num[z];
    53     upd(y),upd(x);
    54 }
    55 void build(int l,int r,int premid){
    56     if(l>r)return;
    57     int mid=(l+r)>>1;
    58     fa[mid]=premid,ch[premid][premid<mid]=mid;
    59     if(mid>1&&mid<n+2)num[mid]=s[mid-2]-'a'+13;else num[mid]=0;
    60     if(l<r)build(l,mid-1,mid),build(mid+1,r,mid),upd(mid);
    61     else size[mid]=1,hash[mid]=num[mid];
    62 }
    63 inline ll gethash(int l,int r){
    64     l=find(rt,l),splay(l,rt);
    65     r=find(rt,r+2),splay(r,ch[l][1]);
    66     return hash[ch[r][0]];
    67 }
    68 inline int query(int a,int b){
    69     if(a>b)swap(a,b);if(num[find(rt,a+1)]!=num[find(rt,b+1)])return 0;
    70     splay(b+1,rt);
    71     if(gethash(a,a+n-b)==gethash(b,n))return n-b+1;
    72     int l,r,mid;
    73     l=1,r=n-b;
    74     while(l<r){
    75         mid=(l+r+1)>>1;
    76         if(gethash(a,a+mid-1)==gethash(b,b+mid-1))l=mid;else r=mid-1;
    77     }
    78     return l;
    79 }
    80 int main(){
    81     scanf("%s",s);n=strlen(s);
    82     for(i=jc[0]=1;i<=n+2;i++)jc[i]=jc[i-1]*197;
    83     rt=(n+2+1)>>1;tot=n+2;build(1,n+2,0);
    84     m=read();char id,z;
    85     while(m--){
    86         for(id=getchar();id<'A'||id>'Z';id=getchar());
    87         x=read();
    88         if(id=='Q')y=read(),printf("%d
    ",query(x,y));
    89         if(id=='R'){
    90             for(z=getchar();z<'a'||z>'z';z=getchar());
    91             change(x,z);
    92         }
    93         if(id=='I'){
    94             for(z=getchar();z<'a'||z>'z';z=getchar());
    95             jc[tot+1]=jc[tot]*197;ins(x,z);n++;
    96         }
    97     }
    98     return 0;
    99 }
    View Code

    1014: [JSOI2008]火星人prefix

    Time Limit: 10 Sec  Memory Limit: 162 MB

    Description

    火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,火星人定义了一个函数LCQ(x, y),表示:该字符串中第x个字符开始的字串,与该字符串中第y个字符开始的字串,两个字串的公共前缀的长度。比方说,LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0 在研究LCQ函数的过程中,火星人发现了这样的一个关联:如果把该字符串的所有后缀排好序,就可以很快地求出LCQ函数的值;同样,如果求出了LCQ函数的值,也可以很快地将该字符串的后缀排好序。 尽管火星人聪明地找到了求取LCQ函数的快速算法,但不甘心认输的地球人又给火星人出了个难题:在求取LCQ函数的同时,还可以改变字符串本身。具体地说,可以更改字符串中某一个字符的值,也可以在字符串中的某一个位置插入一个字符。地球人想考验一下,在如此复杂的问题中,火星人是否还能够做到很快地求取LCQ函数的值。

    Input

    第一行给出初始的字符串。第二行是一个非负整数M,表示操作的个数。接下来的M行,每行描述一个操作。操作有3种,如下所示: 1、 询问。语法:Q x y,x, y均为正整数。功能:计算LCQ(x, y) 限制:1 <= x, y <= 当前字符串长度。 2、 修改。语法:R x d,x是正整数,d是字符。功能:将字符串中第x个数修改为字符d。限制:x不超过当前字符串长度。 3、 插入:语法:I x d,x是非负整数,d是字符。功能:在字符串第x个字符之后插入字符d,如果x = 0,则在字符串开头插入。限制:x不超过当前字符串长度。

    Output

    对于输入文件中每一个询问操作,你都应该输出对应的答案。一个答案一行。

    Sample Input

    madamimadam
    7
    Q 1 7
    Q 4 8
    Q 10 11
    R 3 a
    Q 1 7
    I 10 a
    Q 2 11

    Sample Output

    5
    1
    0
    2
    1

    HINT

    数据规模:

    对于100%的数据,满足:

    1、 所有字符串自始至终都只有小写字母构成。

    2、 M <= 150,000

    3、 字符串长度L自始至终都满足L <= 100,000

    4、 询问操作的个数不超过10,000个。

    对于第1,2个数据,字符串长度自始至终都不超过1,000

    对于第3,4,5个数据,没有插入操作。

  • 相关阅读:
    spring mvc之DispatcherServlet类分析
    python根据操作系统类型调用特定模块
    C#编写windows服务程序
    写在开始前---多端小系统结构
    写在开始前---web异常处理
    java反射
    写在开始前---简单业务分层
    写在开始前---ajax中的会话过期与重新登录
    一个简易的netty udp服务端
    google的python语言规范
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5107420.html
Copyright © 2011-2022 走看看