CF1437G Death DBMS
Pro:
https://www.luogu.com.cn/problem/CF1437G
给定一个大小为n的字符串集合,每个字符串有一个初始为0的权值
支持以下q次操作
1.把第\(x\)个字符串的权值改为\(k\)
2.给定一个字符串s,求出字符串集合中所有在s中出现过的字符串的权值的最大值
Sol:
显然考虑AC自动机+树链剖分
#include<bits/stdc++.h>
#define N 1500000
#define db double
#define ll long long
#define ldb long double
#define ull unsigned long long
using namespace std;
const int h=3,ki=149,mo=998244353;
inline int inc(int x,int k){x+=k;return x>=mo?x-mo:x;}
inline int dec(int x,int k){x-=k;return x<0?x+mo:x;}
inline int read()
{
char ch=0;
int x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
return x*flag;
}
inline void write(int x)
{
if(!x)return (void)putchar(48);
if(x<0)putchar(45),x=-x;
int len=0,p[20];
while(x)p[++len]=x%10,x/=10;
for(int i=len;i>=1;i--)putchar(p[i]+48);
}
const db eps=1e-7,inf=1e9+7,pi=acos(-1);
inline db Read(){db x;scanf("%lf",&x);return x;}
inline void Write(db x){printf("%lf",x);}
char s[N];
int rt=1,size=1,f[N],po[N],nxt[N][26];
void insert(int id)
{
int n=strlen(s),x=rt;
for(int i=0;i<n;i++)
{
int k=s[i]-'a';
if(!nxt[x][k])nxt[x][k]=++size;
x=nxt[x][k];
}
po[id]=x;
}
queue<int>q;
void build()
{
q.push(rt);
for(int i=0;i<26;i++)nxt[0][i]=rt;
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=0;i<26;i++)
if(nxt[x][i])f[nxt[x][i]]=nxt[f[x]][i],q.push(nxt[x][i]);
else nxt[x][i]=nxt[f[x]][i];
}
}
struct edge{int to,nxt;}e[N*2];
int num,head[N];
inline void add(int x,int y){e[++num]={y,head[x]};head[x]=num;}
int times,p[N],id[N],fa[N],sz[N],dep[N],son[N],top[N];
void dfs1(int x,int t)
{
sz[x]=1;dep[x]=t;
for(int i=head[x];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(dep[to])continue;
dfs1(to,t+1);
fa[to]=x;sz[x]+=sz[to];
if(sz[son[x]]<sz[to])son[x]=to;
}
}
void dfs2(int x,int tp)
{
p[id[x]=++times]=x;top[x]=tp;
if(son[x])dfs2(son[x],tp);
for(int i=head[x];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(top[to])continue;
dfs2(to,to);
}
}
struct Segment_Tree
{
#define lson o<<1
#define rson o<<1|1
#define mid ((l+r)>>1)
int maxv[N*4];
inline void pushup(int o){maxv[o]=max(maxv[lson],maxv[rson]);};
void build(){memset(maxv,-1,sizeof(maxv));}
void optset(int o,int l,int r,int q,int k)
{
if(l==r)return (void)(maxv[o]=k);
if(q<=mid)optset(lson,l,mid,q,k);
else optset(rson,mid+1,r,q,k);
pushup(o);
}
int query(int o,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)return maxv[o];
int ans=-1;
if(ql<=mid)ans=max(ans,query(lson,l,mid,ql,qr));
if(qr>mid)ans=max(ans,query(rson,mid+1,r,ql,qr));
return ans;
}
}T;
int query(int x)
{
int ans=-1;
while(x!=1)ans=max(ans,T.query(1,1,size,id[top[x]],id[x])),x=fa[top[x]];
return ans;
}
int w[N];
multiset<int>S[N];
int main()
{
int n=read(),qnum=read();
for(int i=1;i<=n;i++)scanf("%s",s),insert(i);build();
num=-1;memset(head,-1,sizeof(head));
for(int i=2;i<=size;i++)add(f[i],i);
fa[1]=1;dfs1(1,1);dfs2(1,1);T.build();
for(int i=1;i<=n;i++){int t=po[i];S[t].insert(0);T.optset(1,1,size,id[t],0);}
for(int o=1;o<=qnum;o++)
{
int flag=read();
if(flag==1)
{
int x=read(),k=read(),t=po[x];
S[t].erase(S[t].find(w[x]));S[t].insert(k);w[x]=k;
T.optset(1,1,size,id[t],*S[t].rbegin());
}
if(flag==2)
{
scanf("%s",s);
int len=strlen(s),ans=-1;
for(int i=0,x=1;i<len;i++)x=nxt[x][s[i]-'a'],ans=max(ans,query(x));
write(ans);putchar('\n');
}
}
return 0;
}
但是我们不妨考虑一下怎么用SAM来做这个题
一样是考虑树剖维护
但是,可能会出现这种情况
原串abcd
询问bcd
结果abcd和bcd在一个节点
导致查询错误
这个的话
两个解决办法
一种是把询问的字符串也全部加到sam里面去
使它们强行断开
另一种方法可以考虑每个节点单独开一个一长度为下标的动态开点线段树
里面存贮长度为i的最大权值
由于相同长度的也可能有多个串
所以叶子节点要用set来维护
。。。。
然后胡乱写上个200行就好了
#include<bits/stdc++.h>
#define N 1100000
#define M 6600000
#define db double
#define ll long long
#define ldb long double
#define ull unsigned long long
using namespace std;
const int h=3,ki=149,mo=998244353;
inline int inc(int x,int k){x+=k;return x>=mo?x-mo:x;}
inline int dec(int x,int k){x-=k;return x<0?x+mo:x;}
inline int read()
{
char ch=0;
int x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
return x*flag;
}
inline void write(int x)
{
if(!x)return (void)putchar(48);
if(x<0)putchar(45),x=-x;
int len=0,p[20];
while(x)p[++len]=x%10,x/=10;
for(int i=len;i>=1;i--)putchar(p[i]+48);
}
const db eps=1e-7,inf=1e9+7,pi=acos(-1);
inline db Read(){db x;scanf("%lf",&x);return x;}
inline void Write(db x){printf("%lf",x);}
char ch[N];
int root=1,size=1,last=1;
struct node{int pos,len,lnk,nxt[27];}s[N];
void build(int k)
{
int cur=++size,p=last;last=cur;
s[cur].pos=s[p].len;s[cur].len=s[p].len+1;
while(p&&!s[p].nxt[k])s[p].nxt[k]=cur,p=s[p].lnk;
if(!p){s[cur].lnk=root;return;}
int q=s[p].nxt[k];
if(s[p].len+1==s[q].len)s[cur].lnk=q;
else
{
int clone=++size;
s[clone]=s[q];s[clone].len=s[p].len+1;
while(p&&s[p].nxt[k]==q)s[p].nxt[k]=clone,p=s[p].lnk;
s[q].lnk=s[cur].lnk=clone;
}
}
struct edge{int to,nxt;}e[N*2];
int num,head[N];
inline void add(int x,int y){e[++num]={y,head[x]};head[x]=num;}
int times,p[N],po[N],fa[N],id[N],sz[N],dep[N],top[N],son[N];
void dfs1(int x,int t)
{
sz[x]=1;dep[x]=t;
for(int i=head[x];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(dep[to])continue;
dfs1(to,t+1);
fa[to]=x;sz[x]+=sz[to];
if(sz[son[x]]<sz[to])son[x]=to;
}
}
void dfs2(int x,int tp)
{
p[++times]=x;id[x]=times;top[x]=tp;
if(son[x])dfs2(son[x],tp);
for(int i=head[x];i!=-1;i=e[i].nxt)
{
int to=e[i].to;
if(top[to])continue;
dfs2(to,to);
}
}
struct Segment_Tree
{
#define lson o<<1
#define rson o<<1|1
#define mid ((l+r)>>1)
int maxv[N*4];
void build(){memset(maxv,-1,sizeof(maxv));}
void optset(int o,int l,int r,int q,int k)
{
if(l==r)return (void)(maxv[o]=k);
if(q<=mid)optset(lson,l,mid,q,k);
else optset(rson,mid+1,r,q,k);
maxv[o]=max(maxv[lson],maxv[rson]);
}
int query(int o,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr)return maxv[o];
int ans=-1;
if(ql<=mid)ans=max(ans,query(lson,l,mid,ql,qr));
if(qr>mid)ans=max(ans,query(rson,mid+1,r,ql,qr));
return ans;
}
#undef lson
#undef rson
#undef mid
}T;
int query(int x,int y)
{
if(!x)return -1;
int ans=-1;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans=max(ans,T.query(1,1,size,id[top[x]],id[x]));
x=fa[top[x]];
}
if(id[x]>id[y])swap(x,y);
ans=max(ans,T.query(1,1,size,id[x],id[y]));
return ans;
}
int f[N],rt[N],length[N];
multiset<int>S[N];
multiset<int>::iterator it;
struct Segment_Tree_
{
#define lson lc[o]
#define rson rc[o]
#define mid ((l+r)>>1)
multiset<int>g[M];
int size,lc[M],rc[M],maxv[M];
void optset(int &o,int l,int r,int q,int x,int y)
{
if(!o)o=++size;
if(l==r)
{
if(x!=-1)g[o].erase(g[o].find(x));
g[o].insert(y);maxv[o]=*g[o].rbegin();
return;
}
if(q<=mid)optset(lson,l,mid,q,x,y);
else optset(rson,mid+1,r,q,x,y);
maxv[o]=-1;
if(lson)maxv[o]=max(maxv[o],maxv[lson]);
if(rson)maxv[o]=max(maxv[o],maxv[rson]);
}
int query(int o,int l,int r,int ql,int qr)
{
if(!o)return -1;
if(ql<=l&&r<=qr)return maxv[o];
int ans=-1;
if(ql<=mid)ans=max(ans,query(lson,l,mid,ql,qr));
if(qr>mid)ans=max(ans,query(rson,mid+1,r,ql,qr));
return ans;
}
}F;
int sss,qwq[N];
int main()
{
int cnt=read(),qnum=read(),maxn=0;
for(int o=1;o<=cnt;o++)
{
scanf("%s",ch);
int len=strlen(ch);
for(int i=0;i<len;i++)build(ch[i]-'a'),qwq[++sss]=ch[i]-'a';
build(26);
int x=1;
length[o]=len;
maxn=max(maxn,len);
}
for(int o=1,t=0;o<=cnt;o++)
{
int x=1;
for(int i=1;i<=length[o];i++)x=s[x].nxt[qwq[++t]];
po[o]=x;
}
num=-1;memset(head,-1,sizeof(head));
for(int i=2;i<=size;i++)add(s[i].lnk,i);
dfs1(1,1);dfs2(1,1);T.build();
for(int i=1;i<=cnt;i++)
{
int t=po[i];
S[t].insert(0);
F.optset(rt[t],1,maxn,length[i],-1,0);
T.optset(1,1,size,id[t],0);
}
int ttt=0;
for(int o=1;o<=qnum;o++)
{
int flag=read();
if(flag==1)
{
int x=read(),k=read(),t=po[x];
it=S[t].find(f[x]);
S[t].erase(it);
S[t].insert(k);
T.optset(1,1,size,id[t],*S[t].rbegin());
F.optset(rt[t],1,maxn,length[x],f[x],k);
f[x]=k;
}
if(flag==2)
{
scanf("%s",ch);
int ans=-1,len=strlen(ch);
for(int i=0,x=1,tot=0;i<len;i++)
{
int k=ch[i]-'a';
while(x!=1&&!s[x].nxt[k])x=s[x].lnk,tot=s[x].len;
if(s[x].nxt[k])x=s[x].nxt[k],tot++;
ans=max(ans,query(s[x].lnk,1));
if(x!=1)ans=max(ans,F.query(rt[x],1,maxn,1,tot));
}
write(ans);putchar('\n');
}
}
return 0;
}