• BZOJ1396&2865 识别子串 【后缀自动机 + 线段树】


    题目

    输入格式

    一行,一个由小写字母组成的字符串S,长度不超过10^5

    输出格式

    L行,每行一个整数,第i行的数据表示关于S的第i个元素的最短识别子串有多长.

    输入样例

    agoodcookcooksgoodfood

    输出样例

    1

    2

    3

    3

    2

    2

    3

    3

    2

    2

    3

    3

    2

    1

    2

    3

    3

    2

    1

    2

    3

    4

    题解

    BZOJ AC200纪念,,

    这两题题干是一样的,但唯一不同的是。。后者卡空间【MLE得飞起】
    先说解法:
    我们知道后缀自动机上的parent树的每个节点子树中叶子的数量就是该节点表示的串的出现次数
    显然我们要找的是子树叶子数为1,即代表出现次数为1的节点

    parent树中的节点,要么是叶子节点,要么有至少两个儿子

    由上面这个性质我们可以知道满足条件的只有叶子结点
    所以我们连序都不用排了,直接统计不被父亲指针指向的节点

    对于节点i,其表示的串为长度为([step[pre[i]] + 1,step[i]])的串【pre为parent树父亲节点】
    由于该串是唯一的,所以该串表示的最小串为后缀的子串都是唯一的
    我们令其最小串为[l,r],其中(l = step[i] - step[pre[i]],r = step[i])
    我们分为两类:
    ①被最小串包含的位置[l,r],更新其最短识别长度为(r - l + 1)
    ②超出最小串的位置[1,l-1],更新其最短识别长度为(r - i + 1)【i为字符位置】

    那么我们可以开两颗线段树分别维护①和②的最小值,最后输出时二者取最小即可【维护②的先不减i,输出时再减】
    什么意思?每个位置会被两种形式的长度更新,①是一个值,②是一个值还要减去自身的位置,②不好处理,我们分开保存

    T1就搞完了~~

    等等,T2呢?
    原来是数据范围变大了,改大,一交,雾草。。MLE
    = =
    何破?
    ①改用后缀数组【还没写】
    ②将ch改为map保存【好吧我就是这样A的】

    T2太丢脸,贴T1代码吧,,

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    #define ls (u << 1)
    #define rs (u << 1 | 1)
    using namespace std;
    const int maxn = 200005,maxm = 400005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
    	return out * flag;
    }
    int pre[maxn],ch[maxn][26],step[maxn],val[maxn],cnt,last,n;
    char s[maxn];
    void ins(int x){
    	int p = last,np = ++cnt;
    	last = np; step[np] = step[p] + 1;
    	while (p && !ch[p][x]) ch[p][x] = np,p = pre[p];
    	if (!p) pre[np] = 1;
    	else {
    		int q = ch[p][x];
    		if (step[q] == step[p] + 1) pre[np] = q;
    		else {
    			int nq = ++cnt; step[nq] = step[p] + 1;
    			memcpy(ch[nq],ch[q],sizeof(ch[q]));
    			pre[nq] = pre[q]; pre[q] = pre[np] = nq;
    			while (ch[p][x] == q) ch[p][x] = nq,p = pre[p];
    		}
    	}
    }
    struct Seg{
    	int mn[2 * maxn],tag[2 * maxn];
    	Seg(){for (int i = 0; i < maxm; i++) mn[i] = tag[i] = INF;}
    	void pd(int u){
    		if (tag[u] != INF){
    			mn[ls] = min(mn[ls],tag[u]); tag[ls] = min(tag[ls],tag[u]);
    			mn[rs] = min(mn[rs],tag[u]); tag[rs] = min(tag[rs],tag[u]);
    			tag[u] = INF;
    		}
    	}
    	void modify(int u,int l,int r,int L,int R,int v){
    		if (L > R) return;
    		if (l >= L && r <= R){
    			mn[u] = min(mn[u],v);
    			tag[u] = min(tag[u],v);
    			return;
    		}
    		pd(u);
    		int mid = l + r >> 1;
    		if (mid >= L) modify(ls,l,mid,L,R,v);
    		if (mid < R) modify(rs,mid + 1,r,L,R,v);
    		mn[u] = min(mn[ls],mn[rs]);
    	}
    	int query(int u,int l,int r,int pos){
    		if (l == r) return mn[u];
    		pd(u);
    		int mid = l + r >> 1;
    		if (mid >= pos) return query(ls,l,mid,pos);
    		else return query(rs,mid + 1,r,pos);
    	}
    }A,B;
    void solve(){
    	REP(i,cnt) val[i] = 1;
    	REP(i,cnt) val[pre[i]] = 0;
    	REP(i,cnt) if (val[i]){
    		int l = step[i] - step[pre[i]],r = step[i];
    		A.modify(1,1,n,l,r,r - l + 1);
    		B.modify(1,1,n,1,l - 1,r + 1);
    	}
    	REP(i,n)
    		printf("%d
    ",min(A.query(1,1,n,i),B.query(1,1,n,i) - i));
    }
    int main(){
    	//freopen("in.txt","r",stdin);
    	//freopen("out1.txt","w",stdout);
    	scanf("%s",s + 1);
    	n = strlen(s + 1); cnt = last = 1;
    	REP(i,n) ins(s[i] - 'a');
    	solve();
    	return 0;
    }
    
    
  • 相关阅读:
    7.4 List集合
    vue学习笔记
    javaWEB中web.xml配置文件相关
    maven常用dos命令
    Oracle,sqlserver,mySQl的区别和联系:
    oracle数据库视图,序列,索引的sql语句查看
    java 异常处理
    线程专题
    package、folder和source folder的区别
    Java内存分配之堆、栈和常量池
  • 原文地址:https://www.cnblogs.com/Mychael/p/8311818.html
Copyright © 2020-2023  润新知