「雅禮集訓 2017 Day7」事情的相似度
阿新 • • 發佈:2020-12-19
一、題目
二、題目
字尾自動機亂殺。
他問的是字首之間的最長字尾,我們對正串建出字尾自動機,然後把字首在自動機上面打上標記。根據字尾自動機的性質,最長字尾就是兩個字首在 \(\tt parent \;tree\) 上 \(\tt lca\) 的 \(len\)
對於一個字首對 \((l,r)\) ,那麼他可以對 \(L\leq l,r\leq R\) 的詢問 \((L,R)\) 產生貢獻。因為是 \(\tt lca\) ,所以可以想到通過樹上啟發式合併找出這些字首對,那麼我們在合併子樹的時候就要考慮子樹之間新產生的點對。
貌似這樣字首對的數量是 \(O(n^2)\) 的,合併的時候我們只需要找最接近的字首,因為貢獻都是一樣的,但是找最接近的能貢獻到的是最多的,所以數量是 \(O(n\log n)\)
那麼時間複雜度 \(O(n\log^2 n)\),最後算貢獻的時候本質上是一個二維偏序,所以直接排序就行了。
#include <cstdio> #include <iostream> #include <algorithm> #include <set> using namespace std; const int M = 200005; int read() { int x=0,f=1;char c; while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;} while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();} return x*f; } int n,m,k,tot,cnt,last,bit[M],f[M],ans[M];char t[M]; set<int> s[M]; struct edge { int v,next; edge(int V=0,int N=0) : v(V) , next(N) {} }e[2*M]; struct node { int fa,ch[2],len; }a[M]; struct zxy { int l,r,x; bool operator < (const zxy &b) const { return r<b.r; } }q[M],p[20*M]; void add(int c) { int p=last,np=last=++cnt; a[np].len=a[p].len+1; for(;p && !a[p].ch[c];p=a[p].fa) a[p].ch[c]=np; if(!p) a[np].fa=1; else { int q=a[p].ch[c]; if(a[q].len==a[p].len+1) a[np].fa=q; else { int nq=++cnt; a[nq]=a[q];a[nq].len=a[p].len+1; a[q].fa=a[np].fa=nq; for(;p && a[p].ch[c]==q;p=a[p].fa) a[p].ch[c]=nq; } } } void dfs(int u,int fa) { for(int i=f[u];i;i=e[i].next) { int v=e[i].v; if(v==fa) continue; dfs(v,u); if(s[u].size()<s[v].size()) swap(s[u],s[v]); set<int>::iterator it,pre,nxt; for(it=s[v].begin();it!=s[v].end();it++) { s[u].insert(*it); pre=nxt=s[u].find(*it);nxt++; if(pre!=s[u].begin()) pre--,p[++k]=zxy{*pre,*it,a[u].len}; if(nxt!=s[u].end()) p[++k]=zxy{*it,*nxt,a[u].len}; s[u].erase(*it); } for(it=s[v].begin();it!=s[v].end();it++) s[u].insert(*it); } } int lowbit(int x) { return x&(-x); } void add(int x,int y) { for(int i=x;i>=1;i-=lowbit(i)) bit[i]=max(bit[i],y); } int ask(int x) { int res=0; for(int i=x;i<=n;i+=lowbit(i)) res=max(res,bit[i]); return res; } signed main() { n=read();m=read(); scanf("%s",t+1); cnt=last=1; for(int i=1;i<=n;i++) { add(t[i]-'0'); s[last].insert(i); } for(int i=2;i<=cnt;i++) { int j=a[i].fa; e[++tot]=edge(i,f[j]),f[j]=tot; e[++tot]=edge(j,f[i]),f[i]=tot; } dfs(1,0); sort(p+1,p+1+k); for(int i=1;i<=m;i++) { int l=read(),r=read(); q[i]=zxy{l,r,i}; } sort(q+1,q+1+m); for(int i=1,j=1;i<=m;i++) { while(j<=k && p[j].r<=q[i].r) add(p[j].l,p[j].x),j++; ans[q[i].x]=ask(q[i].l); } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); }