BZOJ 十连测 可持久化字符串
SOL:
我们发现答案就是 跑一边KMP 那么答案就是i-net[i],
我们考虑在trie上跑KMP,我们发现KMP的复杂度是依赖摊还分析的线性复杂度。如果朴素的KMP做法时间复杂度是不对的。
比如这样一个trie: a
|
a
|
a
/ \
b b
复杂度就退化了。那么我们可以考虑对每一个节点开一个数组:
f[i] 记下当前的节点后查入i元素后的kmp值。
我们可以发现当前节点的f和其net的f是差不多的,只要将net的f copy一遍 ,再讲net的后继插进来就好了。
我们可以用主席树来维护f
O(nlogn)
#include<bits/stdc++.h> using namespace std; #define sight(c) ('0'<=c&&c<='9') #define N 300007 inline void read(int &x){ static char c; for (c=getchar();!sight(c);c=getchar()); for (x=0;sight(c);c=getchar())x=x*10+c-48; } void write(int x){if (x<10) {putchar('0'+x); return;} write(x/10); putchar('0'+x%10);} inline void writeln(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar('\n'); } inline void writel(int x){ if (x<0) putchar('-'),x*=-1; write(x); putchar(' '); } struct Node{ int l,r,x; }te[N<<5]; int tot,anw,n,m,op,fr,at,lastans,l,len[N],rot[N],fp[N],opt,Le; int f[N][21]; #define Mid (l+r>>1) void ins(int X,int & now,int l,int r,int id,int x) { now=++tot; te[now]=te[X]; if (id==Mid) {te[now].x=x;return;} if (id<Mid) ins(te[X].l,te[now].l,l,Mid-1,id,x); else ins(te[X].r,te[now].r,Mid+1,r,id,x); } void que(int X,int l,int r,int x){ if (Mid==x) {anw=te[X].x; return;} if (x<Mid) que(te[X].l,l,Mid-1,x); else que(te[X].r,Mid+1,r,x); } signed main () { freopen("string.in","r",stdin); freopen("string.out","w",stdout); read(n); read(m); read(op); for (int i=1;i<=n;i++) { read(fr); read(at); if (op) fr^=lastans,at^=lastans; fp[i]=at; f[i][0]=fr; l=len[i]=len[fr]+1; for (int j=1;j<=20;j++) f[i][j]=f[f[i][j-1]][j-1]; que(rot[fr],1,m,at); writeln(lastans=(l-len[anw])); opt=i; Le=len[anw]+1; for (int j=20;~j;j--) if (len[f[opt][j]]>=Le) opt=f[opt][j]; ins(rot[anw],rot[i]=++tot,1,m,fp[opt],opt); } return 0; }