主席树|[LOJ]#2720. 「NOI2018」你的名字 后缀自动机+主席树

Solution 【主席树|[LOJ]#2720. 「NOI2018」你的名字 后缀自动机+主席树】首先讲一下一个68分的水法:建广义SAM,然后每次询问完之后暴力撤销,复杂度未知。
这种做法本身复杂度好像就不对,而且也没法扩展,考虑另外的做法。
考虑每个询问串前缀的贡献。首先要保证本质不同,所以先求出每个前缀的最短的没有在之前出现过的后缀,这个可以对每个询问串建SAM求。然后要求出每个前缀的最短的没有在 S S S出现过的后缀,如果是68分,相当于在 S S S的SAM上匹配,求最长匹配的后缀长度。考虑多了 [ l , r ] [l,r] [l,r]限制之后怎么搞,如果匹配到 x x x节点,就相当于在 p a r e n t parent parent树上 x x x的子树中有满足条件的点,这个点一定是 < = r < =r <=r的最大值,因为我们要求的最短没有出现后缀长度=最长出现后缀长度+1,一定是找最大的那个,那么用一个主席树支持求这个就行了。
Code

#include using namespace std; #define LL long long #define pa pair const int Maxn=1000010; const int inf=2147483647; int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar(); } while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); return x*f; } char s[Maxn],str[Maxn<<1]; int n; struct SAM { int son[Maxn<<1][26],mx[Maxn<<1],par[Maxn<<1]; int lst,tot; void init(){lst=tot=1; } void clear() { for(int i=1; i<=tot; i++) { par[i]=mx[i]=0; for(int j=0; j<26; j++)son[i][j]=0; } } void extend(int x) { int p=lst,np=++tot; mx[np]=mx[p]+1; while(p&&!son[p][x])son[p][x]=np,p=par[p]; if(!p)par[np]=1; else { int q=son[p][x]; if(mx[p]+1==mx[q])par[np]=q; else { int nq=++tot; mx[nq]=mx[p]+1; for(int i=0; i<26; i++)son[nq][i]=son[q][i]; par[nq]=par[q]; par[q]=par[np]=nq; while(son[p][x]==q)son[p][x]=nq,p=par[p]; } } lst=np; } }T1,T2; int Len[Maxn],ed[Maxn]; bool mark[Maxn<<1]; int c[Maxn*24],lc[Maxn*24],rc[Maxn*24],cnt=0,root[Maxn<<1]; void insert(int&u,int l,int r,int p) { if(!u)u=++cnt; c[u]++; if(l==r)return; int mid=l+r>>1; if(p<=mid)insert(lc[u],l,mid,p); else insert(rc[u],mid+1,r,p); } void merge(int&u1,int u2) { if(!u1){u1=u2; return; } if(!u2)return; c[u1]+=c[u2]; merge(lc[u1],lc[u2]),merge(rc[u1],rc[u2]); } int query(int L,int R,int l,int r,int k) { if(!R||c[R]==c[L])return -1; if(l==r)return l; int mid=l+r>>1; if(k<=mid)return query(lc[L],lc[R],l,mid,k); int t=query(rc[L],rc[R],mid+1,r,k); if(t!=-1)return t; return query(lc[L],lc[R],l,mid,k); } vectorG[Maxn<<1]; int in[Maxn<<1],out[Maxn<<1],dfn=0; void dfs(int x) { in[x]=++dfn; for(int i=0; i

    推荐阅读