标签:线段树 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