6.18 省选模拟赛 字符串 LCT SAM
LINK:字符串
看起来很难做 考虑一种暴力 建立SAM后每次查询暴力扫儿子。
期望得分10分。实际得分10分。
另外一种发现每次扫儿子过于暴力 可以每次儿子向上做贡献 每次都暴力向上跳。
期望得分10分。实际得分100分。
由此可以发现玄学的暴力非常的强大 可能这就是所谓的暴力出奇迹吧.
考虑离线:这样就可以把SAM给建出来了 进一步的 每次询问是查询子树和。
每次修改是单点修改 可以利用线段树维护dfs序就做完了。
不过其中存在细节 分裂的节点是影响答案的统计的。
怎么处理分裂的节点?注意到 分裂的节点和当前添加的节点权值无关。
如果对于分裂出来的新节点权值赋值为0 那么这样就不太行。
一个简单的想法 对于分裂出的节点 都拥有自己对应的权值 就行了。
不过这一点很难维护 因为之前的询问可能直接就询问到分裂的节点了。
仔细思考 对于分裂的节点来说 我们在其最初的节点被赋值的时候就把被分裂的节点给赋好值即可。
这样就需要在SAM的建立的时候 对每个节点再标记一个时间戳 然后分裂的时候 直接vector在这个时间戳上打好标记在最初节点赋值的时候一并修改就解决了刚才的问题即可。
难写!!!
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<ctime>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<bitset>
#include<list>
#include<map>
#include<set>
#include<utility>
#include<iomanip>
#define RE register
#define ll long long
#define putl(x) printf("%lld\n",x)
#define gt(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define get(x) x=read()
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define vep(p,n,i) for(int i=p;i<n;++i)
#define fep(n,p,i) for(int i=n;i>=p;--i)
#define pii pari<int,int>
#define mod 998244353
#define f(i) t[i].fa
#define pb push_back
#define zz p<<1
#define yy p<<1|1
#define len(i) t[i].len
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
RE int x=0,f=1;RE char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
const int MAXN=500010,maxn=50010<<2;
int T,m,n,last=1,cnt=1,mark,len,id,len1;ll ans;
char a[maxn],b[MAXN];
struct wy
{
int fa,len;
int ch[26];
}t[maxn];
vector<int>g[maxn];
int v[maxn],dfn[maxn],s[maxn],out[maxn],lin[maxn],ver[maxn],nex[maxn],pos[maxn],sj[maxn];
ll sum[maxn<<2];
inline void add(int x,int y)
{
ver[++len1]=y;
nex[len1]=lin[x];
lin[x]=len1;
}
inline void insert(int x)
{
int p=last;
int np=last=++cnt;
len(np)=len(p)+1;
while(p&&!t[p].ch[x])
{
t[p].ch[x]=np;
p=f(p);
}
if(!p)f(np)=1;
else
{
int q=t[p].ch[x];
if(len(q)==len(p)+1)f(np)=q;
else
{
int nq=++cnt;
t[nq]=t[q];
len(nq)=len(p)+1;
f(q)=f(np)=nq;
while(p&&t[p].ch[x]==q)
{
t[p].ch[x]=nq;
p=f(p);
}
}
}
}
inline void insert1(int x,int id)
{
int p=last;
int np=last=++cnt;
len(np)=len(p)+1;sj[np]=id;
while(p&&!t[p].ch[x])
{
t[p].ch[x]=np;
p=f(p);
}
if(!p)f(np)=1;
else
{
int q=t[p].ch[x];
if(len(q)==len(p)+1)f(np)=q;
else
{
int nq=++cnt;
t[nq]=t[q];sj[nq]=sj[q];
len(nq)=len(p)+1;
g[sj[q]].pb(nq);
g[sj[q]].pb(len(nq)-len(f(nq)));
g[sj[q]].pb(q);
g[sj[q]].pb(len(q)-len(nq)-(len(q)-len(f(q))));
f(q)=f(np)=nq;
while(p&&t[p].ch[x]==q)
{
t[p].ch[x]=nq;
p=f(p);
}
}
}
g[id].pb(np);
g[id].pb(len(np)-len(f(np)));
}
inline void dfs(int x)
{
ans+=len(x)-len(f(x));
rep(1,cnt,i)if(f(i)==x)dfs(i);
}
inline void ask()
{
int now=1;
rep(1,len,i)
{
if(!t[now].ch[b[i]-'a'])return ans=0,void();
now=t[now].ch[b[i]-'a'];
}
ans=-(len-len(f(now))-1);
dfs(now);
}
inline void build(int p,int l,int r)
{
if(l==r)
{
sum[p]=v[pos[l]];
return;
}
int mid=(l+r)>>1;
build(zz,l,mid);
build(yy,mid+1,r);
sum[p]=sum[zz]+sum[yy];
}
inline void change(int p,int l,int r,int x,int w)
{
if(l==r)
{
sum[p]+=w;
return;
}
int mid=(l+r)>>1;
if(x<=mid)change(zz,l,mid,x,w);
else change(yy,mid+1,r,x,w);
sum[p]=sum[zz]+sum[yy];
}
inline void dfs1(int x)
{
dfn[x]=++id;pos[id]=x;
for(int i=lin[x];i;i=nex[i])
{
int tn=ver[i];
dfs1(tn);
}
out[x]=id;
}
inline void change(int x,int w)
{
v[x]+=w;
change(1,1,cnt,dfn[x],w);
}
inline ll ask(int p,int l,int r,int L,int R)
{
if(L<=l&&R>=r)return sum[p];
int mid=(l+r)>>1;
if(R<=mid)return ask(zz,l,mid,L,R);
if(L>mid)return ask(yy,mid+1,r,L,R);
return ask(zz,l,mid,L,R)+ask(yy,mid+1,r,L,R);
}
inline void ask(int x)
{
int now=1;ans=0;
for(int i=0;i<g[x].size();++i)
{
if(!t[now].ch[g[x][i]])return;
now=t[now].ch[g[x][i]];
}
if(!v[now])return;
int w1=len(now);
int w2=g[x].size();
ans=-(w2-1-(len(f(now))+1)+1);
ans+=ask(1,1,cnt,dfn[now],out[now]);
}
int main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
scanf("%s",a+1);n=strlen(a+1);
fep(n,1,i)insert(a[i]-'a');
rep(2,cnt,i)v[i]=len(i)-len(f(i));
mark=cnt;
gt(T);gt(m);
if(m<=100)
{
rep(1,m,i)
{
int op;
gt(op);
if(!op)
{
scanf("%s",b+1);
len=strlen(b+1);
if(len>n){ans=0;put(0);}
else
{
reverse(b+1,b+1+len);
ask();putl(ans);
}
}
else
{
scanf("%s",b+1);++n;
int ww=(b[1]-'a'+ans*T)%26;
insert(ww);
}
}
return 0;
}
if(!T)
{
rep(1,m,i)
{
int op;gt(op);
if(!op)
{
scanf("%s",b+1);
len=strlen(b+1);
reverse(b+1,b+1+len);
rep(1,len,j)g[i].pb(b[j]-'a');
s[i]=op;
}
else
{
scanf("%s",b+1);
int ww=(b[1]-'a')%26;
insert1(ww,i);
s[i]=op;
}
}
rep(2,cnt,i)add(f(i),i);
dfs1(1);
build(1,1,cnt);
for(int i=0;i<g[0].size();i+=2)change(g[0][i],g[0][i+1]);
rep(1,m,i)
{
if(s[i]==0)ask(i),putl(ans);
else for(int j=0;j<g[i].size();j+=2)change(g[i][j],g[i][j+1]);
}
}
return 0;
}
期望得分 50.
这题不强制在线我都A了都。
考虑100分。
容易想到每次加入一个节点要实现断边 连边 维护子树和的功能。
上LCT 直接维护即可。这里不考虑维护子树和 而是每个点向上赋值 深度log咋做都对。
也不太好写 注意细节。
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<ctime>
#include<cmath>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<queue>
#include<stack>
#include<deque>
#include<vector>
#include<bitset>
#include<list>
#include<map>
#include<set>
#include<utility>
#include<iomanip>
#define RE register
#define ll long long
#define putl(x) printf("%lld\n",x)
#define gt(x) scanf("%d",&x)
#define put(x) printf("%d\n",x)
#define get(x) x=read()
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define vep(p,n,i) for(int i=p;i<n;++i)
#define fep(n,p,i) for(int i=n;i>=p;--i)
#define pii pari<int,int>
#define mod 998244353
#define f(i) t[i].fa
#define pb push_back
#define zz p<<1
#define yy p<<1|1
#define len(i) t[i].len
using namespace std;
char *fs,*ft,buf[1<<15];
inline char getc()
{
return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
RE int x=0,f=1;RE char ch=getc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
return x*f;
}
const int MAXN=500010,maxn=50010<<2;
int T,m,n,last=1,cnt=1,mark,len,id,len1;ll ans;
char a[maxn],b[MAXN];
struct wy{int fa,len;int ch[26];}t[maxn];
struct LCT
{
#define l(x) c[x][0]
#define r(x) c[x][1]
int c[maxn][2],rev[maxn],s[maxn],fa[maxn];
ll v[maxn],tag[maxn];
inline bool pd(int x){return l(fa[x])==x||r(fa[x])==x;}
inline void add(int x,ll y)
{
v[x]+=y;
tag[x]+=y;
}
inline void rever(int x)
{
swap(l(x),r(x));
rev[x]^=1;
}
inline void pushdown(int x)
{
if(rev[x])
{
rever(l(x));
rever(r(x));
rev[x]=0;
}
if(tag[x])
{
v[l(x)]+=tag[x];
v[r(x)]+=tag[x];
tag[l(x)]+=tag[x];
tag[r(x)]+=tag[x];
tag[x]=0;
}
}
inline void rotate(int x)
{
int old=fa[x],oldf=fa[old],k=c[fa[x]][1]==x;
c[old][k]=c[x][k^1];c[x][k^1]=old;
if(pd(old))c[oldf][c[oldf][1]==old]=x;
if(c[old][k])fa[c[old][k]]=old;
fa[x]=oldf;fa[old]=x;
}
inline void splay(int x)
{
int top=0,y=x;
s[++top]=x;
while(pd(y))s[++top]=fa[y],y=fa[y];
while(top)pushdown(s[top--]);
while(pd(x))
{
int old=fa[x];
if(pd(old))rotate(((c[old][0]==x)^(c[fa[old]][0]==old))?x:old);
rotate(x);
}
}
inline void access(int x)
{
for(int y=0;x;x=fa[y=x])
splay(x),c[x][1]=y;
}
inline void make_root(int x)
{
access(x);
splay(x);
rever(x);
}
inline void LINK(int x,int y)
{
make_root(x);
fa[x]=y;
access(x);
}
inline void cutf(int x)
{
access(x);
splay(x);
fa[l(x)]=0;
l(x)=0;
}
inline void cut(int x,int y)
{
make_root(x);
cutf(y);
}
inline void change(int x,int p)
{
make_root(1);
access(x);
splay(x);
add(x,p);
}
inline ll ask(int x)
{
access(x);
splay(x);
return v[x];
}
}R;
inline void insert(int x)
{
int p=last;
int np=last=++cnt;
len(np)=len(p)+1;
while(p&&!t[p].ch[x])
{
t[p].ch[x]=np;
p=f(p);
}
if(!p)
{
f(np)=1;
R.LINK(np,f(np));
}
else
{
int q=t[p].ch[x];
if(len(q)==len(p)+1)
{
f(np)=q;
R.LINK(np,f(np));
}
else
{
int nq=++cnt;
R.change(q,-len(q)+len(f(q)));
t[nq]=t[q];
len(nq)=len(p)+1;
R.LINK(nq,f(nq));
R.v[nq]=R.ask(q);
R.cut(q,f(q));
R.LINK(np,nq);
R.LINK(q,nq);
f(q)=f(np)=nq;
R.change(nq,len(nq)-len(f(nq)));
R.change(q,len(q)-len(f(q)));
while(p&&t[p].ch[x]==q)
{
t[p].ch[x]=nq;
p=f(p);
}
}
}
R.change(np,len(np)-len(f(np)));
}
inline void ask()
{
ans=0;
int now=1;
fep(len,1,i)
{
if(!t[now].ch[b[i]-'a'])return ans=0,void();
now=t[now].ch[b[i]-'a'];
}
ans=R.ask(now)-len+len(f(now))+1;
}
int main()
{
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
scanf("%s",a+1);n=strlen(a+1);
fep(n,1,i)insert(a[i]-'a');
gt(T);gt(m);
rep(1,m,i)
{
int op;scanf("%d",&op);
scanf("%s",b+1);
if(!op)
{
len=strlen(b+1);
ask();putl(ans);
}
else insert((b[1]-'a'+ans*T)%26);
}
return 0;
}