• [loj2572]字符串


    约定:以下字符串下标从1开始,令$n=|s|$

    对于字符串$s_{1}$和$s_{2}$,定义以下信息——

    定义$s_{1}approx s_{2}$当且仅当$s_{1}[1,l]=s_{2}[1,l]$(其中$l=min(|s_{1}|,|s_{2}|)$)

    定义$s_{1}ll s_{2}$当且仅当$s_{1}<s_{2}$且$s_{1} otapprox s_{2}$,$s_{1}gg s_{2}$当且仅当$s_{1}>s_{2}$且$s_{1} otapprox s_{2}$

    定义$f(s)$为$s$中最小后缀的位置,即$s[f(s),n]=min_{i=1}^{n}s[i,n]$

    结论:若$s=caab$,则$f(s) e |c|+|a|+1$(其中$a,b,c$为任意字符串,且$a,b$非空)

    考虑取另外$|c|+1$和$|c|+2|a|+1$的位置,即求证$aab<ab$或$b<ab$

    当$ab<b$时,前者显然成立,否则由于$b e ab$,后者即成

    $forall xin [1,n]$,$xin S$当且仅当其满足:

    1.$forall 1le yle n,s[x,n] otll s[y,n]$

    2.$forall 1le y<x且2x-yle n,s[y,n] otapprox s[x,n]$

    (这个条件即等价于不存在$s[1,n]=caab$使得$f(s)=|c|+|a|+1$)

    显然,有$f(s)in S$,下面考虑$|S|$的大小——

    结论:$|S|sim o(log n)$

    若$x,yin S$(不妨假设$x<y$),根据第一个性质,则有$s[x,n]approx s[y,n]$

    若$2y-xle n$,即可以得到$s[x,y)=s[y,2y-x)$,与第2个性质矛盾

    因此$2y-x>n$,也即$2|s[y,n]|le |s[x,n]|$,因此将$S$中的$x$写作$n-x+1$从小到大排列后,后一项大于等于前一项的两倍且值域为$[1,n]$,即有$|S|sim o(log n)$

    当求出$s[l,r]$对应的$S$后,$S$中的最大值即为答案,求最大值复杂度为$o(log n)$

    下面,考虑两个字符串$s_{1}$和$s_{2}$,两者的$S$分别为$S_{1}S_{2}$,下面来求$s=s_{1}s_{2}$的$S$

    先将$S_{2}$中所有元素加上$|s_{1}|$,注意到$Ssubseteq S_{1}cup S_{2}$,从小到大枚举$xin S_{1}cup S_{2}$中的元素$x$,并判定能否加入$S_{i}$中,判定只需要考虑$S$中的元素,具体即——

    初始$S$为空,若$S$为空则直接加入,否则令$y$为当前$S_{i}$中的最大值,考虑$s[x,n]$和$s[y,n]$的关系:

    1.$s[x,n]approx s[y,n]$,若$2x-y>n$则加入$x$

    2.$s[x,n]gg s[y,n]$,不加入$x$

    3.$s[x,n]ll s[y,n]$,令$S_{i}={x}$

    比较可以使用二分+哈希,复杂度为$o(log n)$,哈希用分块维护可以做到修改$o(sqrt{n})$

    综上,合并复杂度为$o(log^{2}n)$,即可用线段树维护,初始复杂度为$o(nlog^{2}n)$,单次修改和查询复杂度总复杂度为$o(log^{3}n)$,最终总复杂度为$o(nlog^{2}n+mlog^{3}n+msqrt{n})$,可以通过

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 200005
      4 #define K 500
      5 #define base 500000003
      6 #define mod 998244353
      7 #define L (k<<1)
      8 #define R (L+1)
      9 #define mid (l+r>>1)
     10 struct Data{
     11     int l,r;
     12     vector<int>v;
     13 }f[N<<2];
     14 int n,m,p,x,y,z,inv,Inv,mi[N],inv_mi[N],a[N],bl[N],st[K],ed[K],tag1[K],tag2[K],sum[N];
     15 int qpow(int n,int m){
     16     int s=n,ans=1;
     17     while (m){
     18         if (m&1)ans=1LL*ans*s%mod;
     19         s=1LL*s*s%mod;
     20         m>>=1;
     21     }
     22     return ans;
     23 }
     24 int get_sum(int x,int y){
     25     return 1LL*(inv_mi[x]+mod-inv_mi[y+1])*Inv%mod;
     26 }
     27 int get_hash(int k){
     28     return (sum[k]+1LL*tag1[bl[k]]*mi[k]+1LL*tag2[bl[k]]*get_sum(st[bl[k]],k)%mod*mi[k])%mod;
     29 }
     30 void update_hash(int x,int y,int z){
     31     if (bl[x]==bl[y]){
     32         for(int i=x;i<=y;i++)sum[i]=(sum[i]+1LL*z*get_sum(x,i)%mod*mi[i])%mod;
     33         int s=1LL*z*get_sum(x,y)%mod;
     34         for(int i=y+1;i<=ed[bl[y]];i++)sum[i]=(sum[i]+1LL*s*mi[i]%mod)%mod;
     35         for(int i=bl[y]+1;i<=bl[n];i++)tag1[i]=(tag1[i]+s)%mod;
     36     }
     37     else{
     38         for(int i=x;i<=ed[bl[x]];i++)sum[i]=(sum[i]+1LL*z*get_sum(x,i)%mod*mi[i])%mod;
     39         int s=1LL*z*get_sum(x,ed[bl[x]])%mod;
     40         for(int i=bl[x]+1;i<bl[y];i++){
     41             tag1[i]=(tag1[i]+s)%mod;
     42             tag2[i]=(tag2[i]+z)%mod;
     43             s=(s+1LL*z*get_sum(st[i],ed[i]))%mod;
     44         }
     45         for(int i=st[bl[y]];i<=y;i++)sum[i]=(sum[i]+(1LL*z*get_sum(st[bl[y]],i)+s)%mod*mi[i])%mod;
     46         s=(s+1LL*z*get_sum(st[bl[y]],y))%mod;
     47         for(int i=y+1;i<=ed[bl[y]];i++)sum[i]=(sum[i]+1LL*s*mi[i]%mod)%mod;
     48         for(int i=bl[y]+1;i<=bl[n];i++)tag1[i]=(tag1[i]+s)%mod;
     49     }
     50 }
     51 int query_hash(int x,int y){
     52     return (get_hash(y)-1LL*mi[y-x+1]*get_hash(x-1)%mod+mod)%mod;
     53 }
     54 int lcp(int x,int y,int i){
     55     int l=0,r=i-y+1;
     56     while (l<r){
     57         int midd=(l+r+1>>1);
     58         if (query_hash(x,x+midd-1)==query_hash(y,y+midd-1))l=midd;
     59         else r=midd-1;
     60     }
     61     return l;
     62 }
     63 int cmp(int x,int y,int i){
     64     int l=lcp(x,y,i);
     65     if (l==i-y+1)return 0;
     66     if (query_hash(x+l,x+l)<query_hash(y+l,y+l))return -1;
     67     return 1;
     68 }
     69 Data merge(Data a,Data b){
     70     if (!a.l)return b;
     71     if (!b.l)return a;
     72     Data ans;
     73     ans.l=a.l,ans.r=b.r;
     74     ans.v.clear();
     75     for(int i=0;i<a.v.size();i++){
     76         if (!ans.v.size())ans.v.push_back(a.v[i]);
     77         else{
     78             int x=ans.v.back(),y=a.v[i],p=cmp(x,y,b.r);
     79             if (p>0)ans.v.clear();
     80             if ((p>0)||(!p)&&(2*y-x>b.r))ans.v.push_back(y);
     81         }
     82     }
     83     for(int i=0;i<b.v.size();i++){
     84         if (!ans.v.size())ans.v.push_back(b.v[i]);
     85         else{
     86             int x=ans.v.back(),y=b.v[i],p=cmp(x,y,b.r);
     87             if (p>0)ans.v.clear();
     88             if ((p>0)||(!p)&&(2*y-x>b.r))ans.v.push_back(y);
     89         }
     90     }
     91     return ans;
     92 }
     93 void build(int k,int l,int r){
     94     if (l==r){
     95         f[k].l=f[k].r=l;
     96         f[k].v.push_back(l);
     97         return;
     98     }  
     99     build(L,l,mid);
    100     build(R,mid+1,r);
    101     f[k]=merge(f[L],f[R]);
    102 }
    103 void update(int k,int l,int r,int x,int y){
    104     if ((l>y)||(x>r))return;
    105     if ((x<=l)&&(r<=y))return;
    106     update(L,l,mid,x,y);
    107     update(R,mid+1,r,x,y);
    108     f[k]=merge(f[L],f[R]);
    109 }
    110 Data query(int k,int l,int r,int x,int y){
    111     if ((l>y)||(x>r))return f[0];
    112     if ((x<=l)&&(r<=y))return f[k];
    113     return merge(query(L,l,mid,x,y),query(R,mid+1,r,x,y));
    114 }
    115 int main(){
    116     inv=qpow(base,mod-2),Inv=qpow(mod+1-inv,mod-2);
    117     mi[0]=inv_mi[0]=1;
    118     for(int i=1;i<N;i++)mi[i]=1LL*mi[i-1]*base%mod;
    119     for(int i=1;i<N;i++)inv_mi[i]=1LL*inv_mi[i-1]*inv%mod;
    120     scanf("%d%d",&n,&m);
    121     for(int i=1;i<=n;i++){
    122         bl[i]=i/K+1;
    123         if (!st[bl[i]])st[bl[i]]=i;
    124         ed[bl[i]]=i;
    125     }
    126     for(int i=1;i<=n;i++){
    127         scanf("%d",&a[i]);
    128         a[i]+=base/2;
    129         sum[i]=(1LL*sum[i-1]*base+a[i])%mod;
    130     }
    131     build(1,1,n);
    132     for(int i=1;i<=m;i++){
    133         scanf("%d%d%d",&p,&x,&y);
    134         if (p==1){
    135             scanf("%d",&z);
    136             update_hash(x,y,(z+mod)%mod);
    137             update(1,1,n,x,y);
    138         }
    139         if (p==2)printf("%d
    ",query(1,1,n,x,y).v.back());
    140     }
    141 } 
    View Code
  • 相关阅读:
    结构体和枚举
    [转载]玩转Asp.net MVC 的八个扩展点
    SQLServer处理亿万级别的数据的优化措施
    Lambda表达式
    匿名类型
    单例模式——懒汉式和饿汉式详解
    Cglib动态代理实现原理
    集合的子集
    深入剖析ThreadLocal
    java注解的自定义和使用
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14787603.html
Copyright © 2020-2023  润新知