专项测试(字符串1)
专项测试(字符串1)
说真的,有点难受,代码能力有点弱,所以我决定找时间做猪国杀去
调一个字符串要调一年,想法也很难实现,也很难想出来
但是其实今天这几个题,我认为我还是有可能想到正解的
注意字符串问题极其容易分类讨论,不好处理的就可以暴力处理,分段处理
T1 回文子串
这个算是挺简单的了,但是让我给做麻烦了
其实哈希判回文就行了,而我用的\(manacher\)
于是我就写了\(200\)多行,今天手真累......
AC_code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
int s=0,t=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
return s*t;
}
const int N=1e5+5;
int n,k,q,m;
char a[N],ma[N];
int p[N];
void manacher(){
ma[0]='$';
fo(i,1,n){
ma[i*2-1]='#';
ma[i*2]=a[i];
}
ma[n*2+1]='#';
int id,mx=0;
fo(i,1,n*2+1){
if(i<mx)p[i]=min(p[id*2-i],mx-i);
else p[i]=1;
p[i]=min(p[i],k);
while(ma[i-p[i]]==ma[i+p[i]]&&p[i]<=k)p[i]++;
if(i+p[i]&1)p[i]--;
if(i+p[i]>mx)mx=i+p[i],id=i;
}
return ;
}
struct XDS{
#define ls x<<1
#define rs x<<1|1
int sum[N*4],pn[N*4],tap[N*4];
void pushup(int x){
sum[x]=sum[ls]+sum[rs];
return ;
}
void pushdown(int x,int l,int r){
int mid=l+r>>1;
if(tap[x]){
tap[ls]=tap[rs]=tap[x];
pn[ls]=pn[rs]=tap[x];
if(mid==l&&(l+pn[ls]&1)){
pn[ls]--;
}
if(mid+1==r&&(r+pn[rs]&1)){
pn[rs]--;
}
if(mid!=l){
if(mid-l+1&1){
sum[ls]=(pn[ls]>>1)*(mid-l+1>>1)+(pn[ls]-1>>1)*(mid-l+1>>1);
if(pn[ls]&1){
if(mid&1)sum[ls]+=(pn[ls]>>1);
else sum[ls]+=(pn[ls]-1>>1);
}
else {
if(mid&1)sum[ls]+=(pn[ls]-1>>1);
else sum[ls]+=(pn[ls]>>1);
}
}
else sum[ls]=(pn[ls]>>1)*(mid-l+1>>1)+(pn[ls]-1>>1)*(mid-l+1>>1);
}
else sum[ls]=(pn[ls]>>1);
if(mid+1!=r){
if(r-mid&1){
sum[rs]=(pn[rs]>>1)*(r-mid>>1)+(pn[rs]-1>>1)*(r-mid>>1);
if(pn[rs]&1){
if(r&1)sum[rs]+=(pn[rs]>>1);
else sum[rs]+=(pn[rs]-1>>1);
}
else {
if(r&1)sum[rs]+=(pn[rs]-1>>1);
else sum[rs]+=(pn[rs]>>1);
}
}
else sum[rs]=(pn[rs]>>1)*(r-mid>>1)+(pn[rs]-1>>1)*(r-mid>>1);
}
else sum[rs]=(pn[rs]>>1);
tap[x]=0;
}
return ;
}
void build(int x,int l,int r){
if(l==r)return sum[x]=p[l]>>1,pn[x]=p[l],void();
int mid=l+r>>1;
build(ls,l,mid);build(rs,mid+1,r);
pushup(x);return ;
}
void ins(int x,int l,int r,int ql,int qr,int v){
if(ql>qr)return ;
if(ql<=l&&r<=qr){
pn[x]=tap[x]=v+1;
if(r-l+1&1){
sum[x]=(pn[x]>>1)*(r-l+1>>1)+(pn[x]-1>>1)*(r-l+1>>1);
if(pn[x]&1){
if(r&1)sum[x]+=(pn[x]>>1);
else sum[x]+=(pn[x]-1>>1);
}
else {
if(r&1)sum[x]+=(pn[x]-1>>1);
else sum[x]+=(pn[x]>>1);
}
}
else sum[x]=(pn[x]>>1)*(r-l+1>>1)+(pn[x]-1>>1)*(r-l+1>>1);
return ;
}
pushdown(x,l,r);
int mid=l+r>>1;
if(ql<=mid)ins(ls,l,mid,ql,qr,v);
if(qr>mid)ins(rs,mid+1,r,ql,qr,v);
pushup(x);return ;
}
int query(int x,int l,int r,int ql,int qr){
if(ql>qr)return 0;
if(ql<=l&&r<=qr)return sum[x];
pushdown(x,l,r);
int mid=l+r>>1,ret=0;
if(ql<=mid)ret+=query(ls,l,mid,ql,qr);
if(qr>mid)ret+=query(rs,mid+1,r,ql,qr);
pushup(x);return ret;
}
int puery(int x,int l,int r,int pos){
if(l==r)return pn[x];
pushdown(x,l,r);
int mid=l+r>>1;
if(pos<=mid)return puery(ls,l,mid,pos);
else return puery(rs,mid+1,r,pos);
}
#undef ls
#undef rs
}xds;
struct node{
#define ls x<<1
#define rs x<<1|1
int sum[N*4],tag[N*4];
void pushdown(int x){
tag[ls]=sum[ls]=tag[x];
tag[rs]=sum[rs]=tag[x];
tag[x]=0;
}
void build(int x,int l,int r){
if(l==r)return sum[x]=ma[l]-'a'+1,void();
int mid=l+r>>1;
build(ls,l,mid);build(rs,mid+1,r);
return ;
}
void ins(int x,int l,int r,int ql,int qr,char v){
if(ql>qr)return ;
if(ql<=l&&r<=qr){
sum[x]=tag[x]=v-'a'+1;
return ;
}
if(tag[x])pushdown(x);
int mid=l+r>>1;
if(ql<=mid)ins(ls,l,mid,ql,qr,v);
if(qr>mid)ins(rs,mid+1,r,ql,qr,v);
return ;
}
int query(int x,int l,int r,int pos){
if(l==r)return sum[x];
if(tag[x])pushdown(x);
int mid=l+r>>1;
if(pos<=mid)return query(ls,l,mid,pos);
else return query(rs,mid+1,r,pos);
}
char a(int x){
if(x==0)return '$';
if(x==m+1)return '&';
if(x&1)return '#';
return query(1,1,m,x)-1+'a';
}
}zm;
signed main(){
scanf("%s",a+1);
k=read();q=read();
n=strlen(a+1);
manacher();m=2*n+1;
xds.build(1,1,m);
zm.build(1,1,m);
while(q--){
int tp=read(),l=read(),r=read();
if(tp==1){
char s[10];
scanf("%s",s+1);
zm.ins(1,1,m,l*2,r*2,s[1]);
if(r-l+1<=k+1){
// cout<<"SB"<<endl;
int id,mx=0;
fo(i,max(l*2-k,1ll),min(r*2+k,m)){
if(i<mx)p[i]=min(xds.puery(1,1,m,id*2-i),mx-i);
else p[i]=1;
p[i]=min(p[i],k);
while(zm.a(i-p[i])==zm.a(i+p[i])&&p[i]<=k)p[i]++;
if(i+p[i]&1)p[i]--;
if(i+p[i]>mx)mx=i+p[i],id=i;
// cout<<m<<" "<<i<<" "<<p[i]<<endl;
xds.ins(1,1,m,i,i,p[i]-1);
// cout<<i<<" "<<"SB"<<endl;
}
}
else {
int id,mx=0;
fo(i,max(l*2-k,1ll),min(l*2+k,m)){
if(i<mx)p[i]=min(xds.puery(1,1,m,id*2-i),mx-i);
else p[i]=1;
p[i]=min(p[i],k);
while(zm.a(i-p[i])==zm.a(i+p[i])&&p[i]<=k)p[i]++;
if(i+p[i]&1)p[i]--;
if(i+p[i]>mx)mx=i+p[i],id=i;
xds.ins(1,1,m,i,i,p[i]-1);
}
id=mx=0;
fo(i,max(r*2-k,1ll),min(r*2+k,m)){
if(i<mx)p[i]=min(xds.puery(1,1,m,id*2-i),mx-i);
else p[i]=1;
p[i]=min(p[i],k);
while(zm.a(i-p[i])==zm.a(i+p[i])&&p[i]<=k)p[i]++;
if(i+p[i]&1)p[i]--;
if(i+p[i]>mx)mx=i+p[i],id=i;
xds.ins(1,1,m,i,i,p[i]-1);
}
xds.ins(1,1,m,l*2+k+1,r*2-k-1,k);
}
}
else {
int ans=0;
if(r-l+1<=k+1){
// cout<<"SB"<<" ";
// cout<<"SB"<<endl;
fo(i,max(l*2-1,1ll),min(r*2+1,m)){
// cout<<ma[i]<<" "<<xds.query(1,1,m,i,i)<<endl;
ans+=min(xds.query(1,1,m,i,i),min((r*2+2-i>>1),(i-l*2+2>>1)));
}
// cout<<endl;
}
else {
fo(i,max(l*2-1,1ll),min(l*2+k,m)){
ans+=min(xds.query(1,1,m,i,i),i-l*2+2>>1);
}
fo(i,max(r*2-k,1ll),min(r*2+1,m)){
ans+=min(xds.query(1,1,m,i,i),r*2+2-i>>1);
}
ans+=xds.query(1,1,m,l*2+k+1,r*2-k-1);
}
printf("%lld\n",ans);
}
}
return 0;
}
T2 recollection
其实看错题了,人家给了一颗\(trie\)树,我以为要自己转化,没看见字符都不相等
转化的话,可以直接把同一个节点的儿子都放到已经出现过的这一层的这个字母下
这样就转化好了
考场上想到了在后缀树上找\(LCA\)但是认为这样仍然是\(mathcal{O(n^2logn)}\)的就直接放弃了
没想到一个集合中最深的\(LCA\)一定是\(dfs\)序相邻的两个点
那么这样就可以对后缀树上每个节点维护一个\(set\)直接启发式合并上去就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
int s=0,t=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
return s*t;
}
const int N=3e5+5;
int n,ans,res;
int too[N],val[N];
int a[N],b[N];
int to[N],nxt[N],head[N],vl[N],rp;
void add_edg(int x,int y,int z){
to[++rp]=y;
nxt[rp]=head[x];
head[x]=rp;
vl[rp]=z;
}
set<int> st[N*2];
struct SAM{
struct POT{
int len,fail;
unordered_map<int,int> son;
}tr[N*2];
int seg;
int num[N*2];
SAM(){seg=1;}
int ins(int c,int las){
int p=las,np=++seg;
tr[np].len=tr[p].len+1;
while(p&&!tr[p].son[c])tr[p].son[c]=np,p=tr[p].fail;
if(!p)tr[np].fail=1;
else {
int q=tr[p].son[c];
if(tr[q].len==tr[p].len+1)tr[np].fail=q;
else {
int nq=++seg;
tr[nq]=tr[q];
tr[nq].len=tr[p].len+1;
tr[q].fail=tr[np].fail=nq;
while(p&&tr[p].son[c]==q)tr[p].son[c]=nq,p=tr[p].fail;
}
}
return np;
}
}sam;
int son[N],siz[N],dep[N],fa[N],cc[N];
int top[N],dfn[N],idf[N],cnt;
void dfs_fi(int x,int f){
son[x]=0;siz[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
fa[y]=x;
dep[y]=dep[x]+1;
cc[y]=vl[i];
dfs_fi(y,x);
siz[x]+=siz[y];
if(!son[x]||siz[y]>siz[son[x]])son[x]=y;
}
}
void dfs_se(int x,int f){
top[x]=f;dfn[x]=++cnt;idf[cnt]=x;
if(son[x])dfs_se(son[x],f);
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==son[x])continue;
dfs_se(y,y);
}
}
int LCA(int x,int y){
x=idf[x];y=idf[y];
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
int las[N];
void build_sam(){
queue<int> q;
while(!q.empty())q.pop();
for(int i=head[1];i;i=nxt[i])q.push(to[i]);
las[1]=1;
while(!q.empty()){
int x=q.front();q.pop();
las[x]=sam.ins(cc[x],las[fa[x]]);
// cout<<sam.tr[las[x]].len<<" "<<cc[x]<<endl;
st[las[x]].insert(dfn[x]);
set<int>::iterator it=st[las[x]].find(dfn[x]);
if(it!=st[las[x]].begin())ans=max(ans,dep[LCA(*prev(it),*it)]+sam.tr[las[x]].len);
if(next(it)!=st[las[x]].end())ans=max(ans,dep[LCA(*next(it),*it)]+sam.tr[las[x]].len);
for(int i=head[x];i;i=nxt[i])q.push(to[i]);
// cout<<ans<<endl;
}
// cout<<endl;
}
int buc[N*2],who[N*2];
signed main(){
n=read();
fo(i,2,n){
too[i]=read();
val[i]=read();
add_edg(too[i],i,val[i]);
}
dfs_fi(1,0);dfs_se(1,1);
build_sam();
fo(i,1,sam.seg)buc[sam.tr[i].len]++;
fo(i,1,n)buc[i]+=buc[i-1];
fu(i,sam.seg,1)who[buc[sam.tr[i].len]--]=i;
fu(i,sam.seg,2){
int u=who[i],f=sam.tr[u].fail;
// cout<<u<<" "<<f<<endl;
if(st[u].size()>st[f].size())swap(st[u],st[f]);
for(int j:st[u]){
st[f].insert(j);
set<int>::iterator it=st[f].find(j);
if(it!=st[f].begin())ans=max(ans,dep[LCA(*prev(it),*it)]+sam.tr[f].len);
if(next(it)!=st[f].end())ans=max(ans,dep[LCA(*next(it),*it)]+sam.tr[f].len);
// cout<<"SB"<<" "<<ans<<" "<<idf[*it]<<" "<<idf[*prev(it)]<<" "<<dep[LCA(*prev(it),*it)]<<" "<<idf[*next(it)]<<" "<<dep[LCA(*next(it),*it)]<<" "<<sam.tr[f].len<<endl;
}
}
printf("%d",ans);
return 0;
}
T3 回忆树
这题好像咋做都行,我是用的后缀树
用线段树合并维护出来每一个节点的\(endpos\)
哦对了,我直接搜了一遍树,建立了一个广义后缀自动机
跨越\(LCA\)的哈希,其余的直接在后缀自动机上跑,看看匹配节点的\(endpos\)有几个就行了
我这个虽然复杂度是两个\(log\)但是跑的比一个还快
并且可以扩展到在线做法
AC_code
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
inline int read(){
int s=0,t=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
return s*t;
}
const ull bas=131;
const int N=3e5+5;
ull ba[N],hl[N],ha[N];
int n,q,len;
char a[N];
int le[N],ll,ri[N],lr;
int to[N*2],nxt[N*2],head[N],val[N*2],rp;
void add_edg(int x,int y,int z){
to[++rp]=y;val[rp]=z;
nxt[rp]=head[x];
head[x]=rp;
}
struct SAM{
struct POT{
int len,fail,son[30];
}tr[N*2];
int seg;
SAM(){seg=1;}
int rt[N*2];
struct XDS{
int sum[N*40],ls[N*40],rs[N*40],tot;
void pushup(int x){sum[x]=sum[ls[x]]+sum[rs[x]];}
void ins(int &x,int l,int r,int pos){
if(!x)x=++tot;
if(l==r)return sum[x]++,void();
int mid=l+r>>1;
if(pos<=mid)ins(ls[x],l,mid,pos);
else ins(rs[x],mid+1,r,pos);
pushup(x);return ;
}
int query(int x,int l,int r,int ql,int qr){
if(ql>qr)return 0;
if(!x)return 0;
if(ql<=l&&r<=qr)return sum[x];
int mid=l+r>>1,ret=0;
if(ql<=mid)ret+=query(ls[x],l,mid,ql,qr);
if(qr>mid)ret+=query(rs[x],mid+1,r,ql,qr);
return ret;
}
int merge(int x,int y){
if(!x||!y)return x+y;
int z=++tot;
ls[z]=merge(ls[x],ls[y]);
rs[z]=merge(rs[x],rs[y]);
pushup(z);return z;
}
}xds;
int ins(int c,int las){
if(tr[las].son[c]){
if(tr[tr[las].son[c]].len==tr[las].len+1)return tr[las].son[c];
int p=las,nq=++seg,q=tr[p].son[c];
tr[nq]=tr[q];
tr[nq].len=tr[p].len+1;
tr[q].fail=nq;
while(p&&tr[p].son[c]==q)tr[p].son[c]=nq,p=tr[p].fail;
return nq;
}
int p=las,np=++seg;
tr[np].len=tr[p].len+1;
while(p&&!tr[p].son[c])tr[p].son[c]=np,p=tr[p].fail;
if(!p)tr[np].fail=1;
else {
int q=tr[p].son[c];
if(tr[q].len==tr[p].len+1)tr[np].fail=q;
else {
int nq=++seg;
tr[nq]=tr[q];
tr[nq].len=tr[p].len+1;
tr[q].fail=tr[np].fail=nq;
while(p&&tr[p].son[c]==q)tr[p].son[c]=nq,p=tr[p].fail;
}
}
return np;
}
int to[N*2],nxt[N*2],head[N*2],rp;
void add_edg(int x,int y){
to[++rp]=y;
nxt[rp]=head[x];
head[x]=rp;
}
void dfs(int x){
for(int i=head[x];i;i=nxt[i]){
int y=to[i];dfs(y);
rt[x]=xds.merge(rt[x],rt[y]);
}
}
void build(){
fo(i,2,seg)add_edg(tr[i].fail,i);
dfs(1);
}
}sam;
int siz[N],son[N],top[N];
int dep[N],fa[N],cc[N];
int dfn[N],idf[N],cnt;
int las[N];
void dfs_fi(int x){
son[x]=0;siz[x]=1;
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==fa[x])continue;
fa[y]=x;cc[y]=val[i];
dep[y]=dep[x]+1;
dfs_fi(y);
siz[x]+=siz[y];
if(!son[x]||siz[y]>siz[son[x]])son[x]=y;
}
}
void dfs_se(int x,int f){
top[x]=f;dfn[x]=++cnt;idf[cnt]=x;
if(x!=1){
las[x]=sam.ins(cc[x],las[fa[x]]);
sam.xds.ins(sam.rt[las[x]],1,n,dfn[x]);
// cout<<"SV"<<" "<<las[x]<<" "<<cc[x]<<" "<<dfn[x]<<" "<<n<<endl;
}
if(son[x])dfs_se(son[x],f);
for(int i=head[x];i;i=nxt[i]){
int y=to[i];
if(y==son[x]||y==fa[x])continue;
dfs_se(y,y);
}
}
int LCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
signed main(){
n=read();q=read();
fo(i,2,n){
int x=read(),y=read(),z;
char s[10];scanf("%s",s+1);
z=s[1]-'a'+1;
add_edg(x,y,z);
add_edg(y,x,z);
}las[1]=1;
dfs_fi(1);dfs_se(1,1);
sam.build();
ba[0]=1;fo(i,1,300000)ba[i]=ba[i-1]*bas;
while(q--){
int u=read(),v=read(),ans=0;
int now,liml=0,limr=0;
scanf("%s",a+1);len=strlen(a+1);
int posl=0,posr=0;
now=1;
fo(i,1,len){
if(!sam.tr[now].son[a[i]-'a'+1]){
posr=0;break;
}
posr=now=sam.tr[now].son[a[i]-'a'+1];
}
now=1;reverse(a+1,a+len+1);
fo(i,1,len){
if(!sam.tr[now].son[a[i]-'a'+1]){
posl=0;break;
}
posl=now=sam.tr[now].son[a[i]-'a'+1];
}
int lca=LCA(u,v);ll=lr=0;
if(dep[u]>dep[lca]+len){
now=u;
while(dep[top[now]]>dep[lca]+len){
ans+=sam.xds.query(sam.rt[posl],1,n,dfn[top[now]],dfn[now]);
now=fa[top[now]];
}
liml=idf[dfn[now]-(dep[now]-dep[lca]-len)];
ans+=sam.xds.query(sam.rt[posl],1,n,dfn[liml]+1,dfn[now]);
now=liml;while(now!=lca)le[++ll]=cc[now],now=fa[now];
}
else {
now=u;
while(now!=lca)le[++ll]=cc[now],now=fa[now];
}
if(dep[v]>dep[lca]+len){
now=v;
while(dep[top[now]]>dep[lca]+len){
ans+=sam.xds.query(sam.rt[posr],1,n,dfn[top[now]],dfn[now]);
now=fa[top[now]];
}
limr=idf[dfn[now]-(dep[now]-dep[lca]-len)];
ans+=sam.xds.query(sam.rt[posr],1,n,dfn[limr]+1,dfn[now]);
now=limr;while(now!=lca)ri[++lr]=cc[now],now=fa[now];
}
else {
now=v;
while(now!=lca)ri[++lr]=cc[now],now=fa[now];
}
// cout<<ans<<" "<<posl<<" "<<posr<<" "<<sam.xds.query(sam.rt[posl],1,n,1,n)<<endl;
reverse(a+1,a+len+1);
fo(i,1,lr)le[++ll]=ri[lr-i+1];
fo(i,1,ll)hl[i]=hl[i-1]*bas+le[i];
fo(i,1,len)ha[i]=ha[i-1]*bas+a[i]-'a'+1;
fo(i,len,ll)if(hl[i]-hl[i-len]*ba[len]==ha[len])ans++;
printf("%d\n",ans);
}
return 0;
}
QQ:2953174821