约定:以下字符串下标从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 }