zoukankan      html  css  js  c++  java
  • SWERC2015-I Text Processor

    题意

    给一个长度为(n)的字符串(s),再给定一个(w),问对于所有的(iin [1,n-w+1])(s[i..i+w-1])有多少个不同字串。(n,wle 10^5)

    分析

    统计不同子串个数的问题可以使用后缀树。一个字符串的后缀树的总边长就是这个字符串的不同子串个数。解决这个问题,一个显然的方法就是划窗法,即每次删掉第一个字符,加入最后一个字符,再统计后缀树上边长的变更即可。

    很明显这个方法需要一个在线的后缀树构建算法,可以用Ukkonen来做。那么我们如何求出每次删掉哪个后缀呢?我们删掉的肯定是当前后缀树中最长的后缀,也就是最早添加进去的那个叶子节点。所以我们维护一个队列,每次新建叶子的时候就加入队列中(压缩边也需要),每次删除队头即可。

    代码

    调了很久啊……这个题一定要想好再写(所有题都应该想好再写),会有一些需要注意的地方。好好利用删除的一定是叶子节点这个性质。

    我的方法需要压缩边,即如果一个点只有一条出边,那么把这个点压缩掉。根据压缩后缀树的性质可以得到,每次最多删除一条边,压缩一条边。直接讨论一下now节点是否在这条边上就好啦。

    然后,开long long……子串计数问题一定要注意这个啊!!

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long giant;
    int read() {
    	int x=0,f=1;
    	char c=getchar();
    	for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    	for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    	return x*f;
    }
    const int maxn=2e5+10;
    const int maxc=27;
    giant ans=0,Ans[maxn];
    int w,que[maxn],ql=1,qr=0;
    struct ST {
    	const static int inf=1e8;
    	int t[maxn][maxc],father[maxn],sons[maxn],start[maxn],len[maxn],link[maxn],now,rem,s[maxn],n,leaf,tot,pool[maxn];
    	ST ():now(1),rem(0),n(0),leaf(0),tot(1) {
    		for (int i=1;i<maxn;++i) pool[i]=i;
    		father[1]=0;
    		len[0]=inf;
    	}
    	void erase(int &x) {
    		memset(t[x],0,sizeof t[x]),start[x]=len[x]=link[x]=father[x]=sons[x]=0;
    		pool[tot--]=x;
    		x=0;
    	}
    	int node(int star,int le) {
    		int nw=pool[++tot];
    		start[nw]=star,len[nw]=le,link[nw]=1;
    		return nw;
    	}
    	void add(int c) { // c is a char
    		s[++n]=c,++rem;
    		for (int last=1;rem;) {
    			while (rem>len[t[now][s[n-rem+1]]]) rem-=len[now=t[now][s[n-rem+1]]];
    			int ed=s[n-rem+1];
    			int &v=t[now][ed];
    			int x=s[start[v]+rem-1];
    			if (!v) {
    				father[que[++qr]=v=node(n-rem+1,inf)]=now;
    				++sons[now];
    				link[last]=now;
    				last=now;
    			} else if (x==c) {
    				link[last]=now;
    				last=now;
    				break;
    			} else {
    				int u=node(start[v],rem-1);
    				father[u]=father[v];
    				father[que[++qr]=t[u][c]=node(n,inf)]=u;
    				father[t[u][x]=v]=u,start[v]+=rem-1;
    				if (len[v]<inf) len[v]-=rem-1;
    				sons[link[last]=v=u]=2;
    				last=v;
    			}
    			++leaf;
    			if (now==1) --rem; else now=link[now];
    		}
    	}
    	void compress(int x) {
    		if (!father[x]) return;
    		if (sons[x] && (--sons[x])!=1) return;
    		int i;
    		for (i=1;i<maxc;++i) if (t[x][i]) break;
    		int u=t[x][i];
    		start[u]-=len[x];
    		if (len[u]<inf) len[u]+=len[x];
    		father[u]=father[x];
    		erase(t[father[x]][s[start[x]]]);
    		t[father[u]][s[start[u]]]=u;
    	}
    	void del(int x) { // x is a point 
    		int f=father[x];
    		if (now==f) {
    			if (!rem || t[now][s[n-rem+1]]!=x) {
    				ans-=n-start[x]+1;
    				--leaf;
    				erase(t[f][s[start[x]]]);
    				if (now!=1) now=father[now],rem+=len[f];
    				compress(f);
    				return;
    			}
    			ans-=n-rem-start[x]+1;
    			start[x]=n-rem+1;
    			que[++qr]=x;
    			if (now==1) --rem; else now=link[now];
    		} else {
    			ans-=n-start[x]+1;
    			erase(t[f][s[start[x]]]);
    			compress(f);
    			--leaf;
    		}
    	}
    	void run() {
    		for (int i=1;i<=tot;++i) if (pool[i]!=1) ans+=min(len[pool[i]],n-start[pool[i]]+1);
    	}
    } sut;
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("test.in","r",stdin);
    	freopen("my.out","w",stdout);
    #endif
    	int n,m;
    	static char s[maxn];
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	m=read(),w=read();
    	for (int i=1;i<=w;++i) 
    		sut.add(s[i]-'a'+1);
    	sut.run();
    	Ans[1]=ans;
    	for (int i=w+1;i<=n;++i) {
    		if (ql<=qr) sut.del(que[ql++]); 
    		sut.add(s[i]-'a'+1);
    		ans+=sut.leaf;
    		Ans[i-w+1]=ans;
    	}
    	while (m--) printf("%lld
    ",Ans[read()]);
    	return 0;
    }
    
  • 相关阅读:
    Linux时间子系统之一:clock source(时钟源)【转】
    浅谈linux的死锁检测 【转】
    Linux内核死锁检测机制【转】
    spin_lock、spin_lock_irq、spin_lock_irqsave区别【转】
    Microsoft Security Essential: 微软安全软件
    Linux内核同步机制之(三):memory barrier【转】
    ftrace的使用【转】
    Linux下安装Python-3.3.2【转】
    Linux驱动修炼之道-RTC子系统框架与源码分析【转】
    Python应用与实践【转】
  • 原文地址:https://www.cnblogs.com/owenyu/p/6880151.html
Copyright © 2011-2022 走看看