bzoj 1396 識別子串

2022-03-27 04:56:48 字數 2337 閱讀 4816

題目

\(sam\)+線段樹

我竟然還會寫線段樹真是感人至深

考慮到我們只能計算出現一次的子串,所以我們直接先求乙個子樹和,只對\(|endpos|=1\)的點操作就好了

我們在\(sam\)插入的時候可以先存存好每乙個字首的結尾位置在**,之後我們對於每乙個字首討論其出現次數為\(1\)的字尾

顯然在\(parent\)樹上深度越小的節點的\(len\)就越小,\(|endpos|\)也就越大,於是我們直接從每個字首的結尾節點往上跳,跳到深度最小的\(|endpos|=1\)的節點

這個可以通過樹上倍增做到,不過好像直接暴力看起來更有保障一些

設\(x\)就是我們跳到的點,那麼非常顯然從\(i-len[fa[x]]+1\)到\(i\)這些位置的字尾出現次數超過了\(1\),而從\(1\)到\(i-len[fa[x]]\)這些子串的出現次數為\(1\)

所以對於\([\ 1,i-len[fa[x]]\ ]\)這個區間裡的位置我們都可以標記出乙個其能往後延伸的最近位置,顯然就是\(i\),而我們如果倒著迴圈的話,我們就可以保證\(i\)單減,所以我們甚至可以只用乙個線段樹來通過區間覆蓋進行更新

而對於\([i-len[fa[x]]+1,i]\)這個區間的位置,我們發現其長度都是固定的,為\(len[fa[x]]+1\),但是我們好像不太能保證\(len[fa[x]]+1\)單調

沒有關係啊,我們離線下來排序就好了

**

#include#include#include#include#define maxn 200005

#define re register

#define inf 999999999

#define min(a,b) ((a)

int num,n,lst=1,cnt=1;

char s[maxn>>1];

int to[maxn>>1];

struct e e[maxn];

struct c a[maxn];

int fa[maxn],son[maxn][26],sz[maxn],len[maxn],head[maxn],f[maxn][19],deep[maxn],log_2[maxn];

inline int cmp(c a,c b)

inline void add(int x,int y)

void dfs(int x)

inline void ins(int o,int c)

int x=son[f][c];

if(len[f]+1==len[x])

int y=++cnt;

len[y]=len[f]+1,fa[y]=fa[x],fa[x]=fa[p]=y;

for(re int i=0;i<26;i++) son[y][i]=son[x][i];

while(f&&son[f][c]==x) son[f][c]=y,f=fa[f];

}inline int find(int x)

int l[maxn<<1],r[maxn<<1],tag[maxn<<1],d[maxn>>1],ans[maxn>>1],ans[maxn>>1];

void build(int x,int y,int i)

inline void pushdown(int i)

void change(int x,int y,int val,int i)

pushdown(i);

int mid=l[i]+r[i]>>1;

if(y<=mid) change(x,y,val,i<<1);

else if(x>mid) change(x,y,val,i<<1|1);

else change(x,y,val,i<<1),change(x,y,val,i<<1|1);

}int ask(int pos,int i)

int main()

for(re int i=1;i<=n;i++) d[i]=ask(i,1);

std::sort(a+1,a+n+1,cmp);

build(1,n,1);

for(re int i=1;i<=n;i++) if(a[i].x<=a[i].y) change(a[i].x,a[i].y,a[i].v,1);

for(re int i=1;i<=n;i++) ans[i]=ask(i,1),ans[i]=min(ans[i],d[i]-i+1);

for(re int i=1;i<=n;i++) printf("%d\n",ans[i]);

return 0;

}

BZOJ 1396 識別子串

solution 我得了 能用字尾陣列就一定不用字尾自動機綜合症 感覺用height rank sa 處理字串真的好優雅 雖然其他題上字尾陣列常數比較大 不過這個字尾陣列水了一發似乎就rank1 了 開心 題解就是求出字尾陣列以後維護乙個單調佇列來更新答案啦。include include incl...

Bzoj1396 識別子串

i 1,n i 1,n 求包含 i i 並且在原串 s role presentation style position relative s s中只出現一次的子串的最短長度 因為每個點pa rent p ar en t樹上的父親肯定是當前節點所代表的串的字尾 那麼只出現一次的串就是pa rent ...

BZOJ1396 識別子串

列舉左端點 i 那麼可行的右端點 j 的最小值單調不下降,可以通過雙指標求出,檢驗可以通過在字尾陣列裡檢查相鄰height值做到 o 1 那麼左端點為 i 右端點在 j,n 它對前面一段的貢獻為定值,對後面一段的貢獻為等差數列,線段樹維護即可。時間複雜度 o n log n include incl...