标签:线段树 div 处理 get string i++ def 长度 set
题意:给定参数$k$,维护一个字符串,支持区间覆盖字符和查询,查询是查询区间中有多少个长度$\leq k$的子串是回文串,其中$k\leq50$
$k$很小,考虑从这里入手,我们先用manacher预处理出以每个位置开头有多少个回文串,用线段树存起来
查询$[l,r]$时$[l,r-k+1]$这段可以直接解区间求和,剩下那段单独拿出来做manacher
修改$[l,r]$时$[l,r-k+1]$这段全部变成$k$,把$[l-k+1,l+k-2]$这段拿出来做manacher更新$[l-k+1,l-1]$的值,把$[r-k+2,r+k-1]$这段拿出来做manacher更新$[r-k+2,r]$的值
然而我不会写manacher而且时限很大,所以直接哈希就可以了
#include<stdio.h>
#include<string.h>
typedef unsigned long long ll;
const ll ba=19260817;
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;}
ll fh[50010],bh[50010],b[50010];
ll getf(int l,int r){return fh[r]-fh[l-1]*b[r-l+1];}
ll getb(int l,int r){return bh[l]-bh[r+1]*b[r-l+1];}
int k;
void getpa(char*s,int*c){
int n,i,l,r,mid,ans;
n=strlen(s+1);
memset(c,0,(n+1)<<2);
b[0]=1;
fh[0]=0;
for(i=1;i<=n;i++){
b[i]=b[i-1]*ba;
fh[i]=fh[i-1]*ba+s[i];
}
bh[n+1]=0;
for(i=n;i>0;i--)bh[i]=bh[i+1]*ba+s[i];
for(i=1;i<=n;i++){
l=1;
r=min(i,n-i+1);
while(l<=r){
mid=(l+r)>>1;
if(getf(i-mid+1,i)==getb(i,i+mid-1)){
ans=mid;
l=mid+1;
}else
r=mid-1;
}
if(ans>(k+1)/2)ans=(k+1)/2;
c[i-ans+1]++;
c[i+1]--;
}
for(i=1;i<n;i++){
l=1;
r=min(i,n-i);
ans=0;
while(l<=r){
mid=(l+r)>>1;
if(getf(i-mid+1,i)==getb(i+1,i+mid)){
ans=mid;
l=mid+1;
}else
r=mid-1;
}
if(ans>k/2)ans=k/2;
c[i-ans+1]++;
c[i+1]--;
}
for(i=1;i<=n;i++)c[i]+=c[i-1];
}
struct segi{
int s[200010],t[200010];
void cov(int x,int len,int v){
s[x]=len*v;
t[x]=v;
}
void pushdown(int x,int ln,int rn){
if(t[x]){
cov(x<<1,ln,t[x]);
cov(x<<1|1,rn,t[x]);
t[x]=0;
}
}
void pushup(int x){s[x]=s[x<<1]+s[x<<1|1];}
void modify(int L,int R,int v,int l,int r,int x){
if(L<=l&&r<=R)return cov(x,r-l+1,v);
int mid=(l+r)>>1;
pushdown(x,mid-l+1,r-mid);
if(L<=mid)modify(L,R,v,l,mid,x<<1);
if(mid<R)modify(L,R,v,mid+1,r,x<<1|1);
pushup(x);
}
int query(int L,int R,int l,int r,int x){
if(L<=l&&r<=R)return s[x];
int mid=(l+r)>>1,t=0;
pushdown(x,mid-l+1,r-mid);
if(L<=mid)t+=query(L,R,l,mid,x<<1);
if(mid<R)t+=query(L,R,mid+1,r,x<<1|1);
return t;
}
}ti;
struct segc{
char c[200010];
void pushdown(int x){
if(c[x]){
c[x<<1]=c[x<<1|1]=c[x];
c[x]=0;
}
}
void modify(int L,int R,char v,int l,int r,int x){
if(L<=l&&r<=R){
c[x]=v;
return;
}
pushdown(x);
int mid=(l+r)>>1;
if(L<=mid)modify(L,R,v,l,mid,x<<1);
if(mid<R)modify(L,R,v,mid+1,r,x<<1|1);
}
char query(int p,int l,int r,int x){
if(l==r)return c[x];
int mid=(l+r)>>1;
pushdown(x);
if(p<=mid)
return query(p,l,mid,x<<1);
else
return query(p,mid+1,r,x<<1|1);
}
}tc;
char s[50010];
int tmp[50010],n;
int main(){
int m,i,j,x,y,ans;
scanf("%s%d%d",s+1,&k,&m);
n=strlen(s+1);
for(i=1;i<=n;i++)tc.modify(i,i,s[i],1,n,1);
getpa(s,tmp);
for(i=1;i<=n;i++)ti.modify(i,i,tmp[i],1,n,1);
while(m--){
scanf("%d%d%d",&i,&x,&y);
if(i==1){
scanf("%s",s);
tc.modify(x,y,s[0],1,n,1);
if(y-x+1>=k)ti.modify(x,y-k+1,k,1,n,1);
for(i=max(1,x-k+1),j=1;i<=min(n,x+k-2);i++,j++)s[j]=tc.query(i,1,n,1);
s[j]=0;
getpa(s,tmp);
for(i=max(1,x-k+1),j=1;i<x;i++,j++)ti.modify(i,i,tmp[j],1,n,1);
for(i=max(1,y-k+2),j=1;i<=min(y+k-1,n);i++,j++)s[j]=tc.query(i,1,n,1);
s[j]=0;
getpa(s,tmp);
for(i=max(1,y-k+2),j=1;i<=y;i++,j++)ti.modify(i,i,tmp[j],1,n,1);
}else{
ans=0;
if(y-x+1>=k)ans+=ti.query(x,y-k+1,1,n,1);
for(i=max(x,y-k+2),j=1;i<=y;i++,j++)s[j]=tc.query(i,1,n,1);
s[j]=0;
getpa(s,tmp);
for(i=max(x,y-k+2),j=1;i<=y;i++,j++)ans+=tmp[j];
printf("%d\n",ans);
}
}
}
标签:线段树 div 处理 get string i++ def 长度 set
原文地址:https://www.cnblogs.com/jefflyy/p/9351144.html