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

    [bzoj1014] [JSOI2008] 火星人prefix 题目传送门

    [洛谷P4036] [JSOI2008] 火星人 题目传送门

    先考虑不带插入和修改的情况。

    我们可以先把字符串hash了,用hash值二分答案(我用倍增答案)求出最长公共前缀。

    但是如果有插入修改呢?

    用splay维护hash值,每个节点的值v就是该位字母的值(char-‘a’+1)。

    splay的每个子树都代表字符串的一个部分。

    在每个点上记录一个sum,代表这个点的子树代表的字符串的hash值。

    显然这个值可以用左右子树的sum、该节点的v 以及hash时用的seed的(左子树大小)次幂来表示。

    这样查询、插入和修改都是很简单了。

    在树上转一下,更新或查询即可。

    询问时还是二分答案(倍增答案),利用splay查询hash值进行比较。

    这里还是define了一个empty代表空位置。

    注意check函数的边界判断QwQ

    if( (x+nw>len) || (y+nw>len) ) return false;

    在这里卡了一上午呜呜呜......

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #define empty 100002
      5 #define id(x) (s[f[x]][1]==x)
      6 #define ull unsigned long long
      7 using namespace std;
      8 
      9 int m,len;
     10 char str[100010];
     11 ull hp[100010],v[100010],sum[100010],sd=37;
     12 int s[100010][2],f[100010],root,sz[100010];
     13 
     14 void pushup(int p)
     15 {
     16     sz[p]=sz[s[p][0]]+sz[s[p][1]]+1;
     17     sum[p]=sum[s[p][0]]*hp[sz[s[p][1]]+1]+sum[s[p][1]]+v[p]*hp[sz[s[p][1]]];
     18 }
     19 
     20 int build(int l,int r)
     21 {
     22     if(l>r)return empty;
     23     int mid=(l+r)>>1;
     24     s[mid][0]=build(l,mid-1);
     25     s[mid][1]=build(mid+1,r);
     26     if(s[mid][0]!=empty)f[s[mid][0]]=mid;
     27     if(s[mid][1]!=empty)f[s[mid][1]]=mid;
     28     v[mid]=str[mid]-'a'+1;
     29     pushup(mid);
     30     return mid;
     31 }
     32 
     33 void rotate(int p)
     34 {
     35     int fa=f[p];
     36     int k=id(p);
     37     s[fa][k]=s[p][!k];
     38     s[p][!k]=fa;
     39     s[f[fa]][id(fa)]=p;
     40     f[p]=f[fa];
     41     f[s[fa][k]]=fa;
     42     f[fa]=p;
     43     pushup(fa);
     44     pushup(p);
     45 }
     46 
     47 void splay(int p,int g)
     48 {
     49     while(f[p]!=g)
     50     {
     51         int fa=f[p];
     52         if(f[fa]==g)
     53         {
     54             rotate(p);
     55             break;
     56         }
     57         if(id(p)^id(fa))rotate(p);
     58         else rotate(fa);
     59         rotate(p);
     60     }
     61     if(g==empty)root=p;
     62 }
     63 
     64 int qpos(int p,int rk)
     65 {
     66     if(sz[s[p][0]]>=rk)return qpos(s[p][0],rk);
     67     else if(sz[s[p][0]]+1==rk)return p;
     68     else return qpos(s[p][1],rk-1-sz[s[p][0]]);
     69 }
     70 
     71 bool check(int x,int y,int nw)
     72 {
     73     if((x+nw>len)||(y+nw>len))
     74         return false;
     75     splay(qpos(root,x),empty);
     76     splay(qpos(root,x+nw+1),root);
     77     ull hx=sum[s[s[root][1]][0]];
     78     splay(qpos(root,y),empty);
     79     splay(qpos(root,y+nw+1),root);
     80     ull hy=sum[s[s[root][1]][0]];
     81     return (hx==hy);
     82 }
     83 
     84 void query()
     85 {
     86     int x,y;
     87     scanf("%d%d",&x,&y);
     88     int ans=0;
     89     for(int i=20;i>=0;i--)
     90         if(check(x,y,ans|(1<<i)))ans|=(1<<i);
     91     printf("%d
    ",ans);
     92 }
     93 
     94 void repair()
     95 {
     96     char c[5];
     97     int x;
     98     scanf("%d",&x);
     99     scanf("%s",c+1);
    100     int tar=qpos(root,x+1);
    101     splay(tar,empty);
    102     v[root]=c[1]-'a'+1;
    103     pushup(root);
    104 }
    105 
    106 void in()
    107 {
    108     char c[5];
    109     int x;
    110     scanf("%d",&x);
    111     scanf("%s",c+1);
    112     splay(qpos(root,x+1),empty);
    113     splay(qpos(root,x+2),root);
    114     f[++len]=s[root][1];
    115     s[s[root][1]][0]=len;
    116     v[len]=sum[len]=c[1]-'a'+1;
    117     sz[len]=1;
    118     pushup(s[root][1]);
    119     pushup(root);
    120 }
    121 
    122 int main()
    123 {
    124     scanf("%s",str+1);
    125     len=strlen(str+1);
    126     hp[0]=1;
    127     for(int i=1;i<=100005;i++)hp[i]=hp[i-1]*sd;
    128     for(int i=0;i<=100001;i++)s[i][0]=s[i][1]=f[i]=empty;
    129     str[0]=str[++len]='a'-1;
    130     root=build(0,len);
    131     scanf("%d",&m);
    132     while(m--)
    133     {
    134         char op[5];
    135         scanf("%s",op+1);
    136         if(op[1]=='Q')query();
    137         if(op[1]=='R')repair();
    138         if(op[1]=='I')in();
    139     }
    140     return 0;
    141 }
    [JSOI2008] 火星人

    之前多次提到倍增答案,那么什么是倍增答案呢?

    想知道的点这里哦~

  • 相关阅读:
    cliconfg
    SQL 校验身份证格式
    常用MIME类型汇总
    SqlBulkCopy批量将Excel(Aspose)数据导入至SQL Server
    C#生成图片验证码
    SqlServer PIVOT函数快速实现行转列,UNPIVOT实现列转行
    SQL Server 中 EXEC 与 SP_EXECUTESQL 的区别
    C#常用加密方式
    CURSOR 游标使用示例
    linux命令
  • 原文地址:https://www.cnblogs.com/cervusy/p/9609103.html
Copyright © 2011-2022 走看看