zoukankan      html  css  js  c++  java
  • bzoj1396 识别子串

    题面
    https://www.lydsy.com/JudgeOnline/problem.php?id=1396
    首先,对于题目所说的T在S中只出现一次这个要求,
    可以利用后缀自动机的parent树的叶子节点的性质来满足要求。
    显然所有满足T在S中只出现过一次的子串就是parent树所有叶子节点的right集合的并集。
    考虑怎么去找到最小值。
    对于一个叶子节点来说,其right集合中所有串的右端点显然是一样的,左端点依次向右,长度依次递减,直到左端点不再属于这个点的right集合位置。
    可以用一个式子来描述rifht集合的左端点的范围【id[x]-s[x].len+1,id[x]-s[s[x].link].len】。
    进一步地发现这个right集合对答案的贡献是一条斜线和一条水平线(这里所说的贡献是使答案对其取min)
    因为对于【id[x]-s[x].len+1,id[x]-s[s[x].link].len】可以产生的贡献随着长度依次递减,是一条斜线。
    而对于【id[x]-s[s[x].link].len+1,id[x]】,由于左端点位于这个位置时,不再满足“T在S中只出现过一次”这一要求。
    因此可以产生的贡献只能是刚才那条斜线的右端点的水平延长线。
    分析完操作后,考虑怎么实现这两个区间操作。
    有一个自闭的想法是直接强行上一个李超线段树就完事了,然而并没有必要。
    发现由于只关心最后的答案,可以离线,即把斜线和水平线分开做,跑两次,分别用不同的线段树维护,这样就simple了很多。

    #include<iostream>
    #include<cctype>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<ctime>
    #include<cstdlib>
    #include<algorithm>
    #define N 330000
    #define L 300000
    #define eps 1e-7
    #define inf 1e9+7
    #define ll long long
    using namespace std;
    inline int read()
    {
    	char ch=0;
    	int x=0,flag=1;
    	while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
    	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*flag;
    }
    char ch[N];
    bool flag[N];
    int root=1,size=1,last=1,id[N];
    struct node{int len,link,nxt[26];}s[N];
    void insert(int k)
    {
    	int cur=++size,p=last;
    	s[cur].len=s[p].len+1;
    	while(p&&!s[p].nxt[k])
    	{
    		s[p].nxt[k]=cur;
    		p=s[p].link;
    	}
    	last=cur;
    	if(!p){s[cur].link=root;return;}
    	int q=s[p].nxt[k];
    	if(s[q].len==s[p].len+1)s[cur].link=q;
    	else
    	{
    		int clone=++size;
    		s[clone]=s[q];
    		s[clone].len=s[p].len+1;
    		while(p&&s[p].nxt[k]==q)
    		{
    			s[p].nxt[k]=clone;
    			p=s[p].link;
    		}
    		s[q].link=s[cur].link=clone;
    	}
    }
    struct Segment_Tree
    {
    	#define lson o<<1
    	#define rson o<<1|1
    	#define mid ((l+r)>>1)
    	int num,setv[N*4];
    	inline void pushdown(int o,int l,int r)
    	{
    		if(setv[o]==inf)return;
    		setv[lson]=min(setv[lson],setv[o]);
    		setv[rson]=min(setv[rson],setv[o]-(mid-l+1));
    		setv[o]=inf;
    	}
    	void build(int o,int l,int r)
    	{
    		setv[o]=inf;
    		if(l==r)return;
    		build(lson,l,mid);
    		build(rson,mid+1,r);
    	}
    	void optset(int o,int l,int r,int ql,int qr)
    	{
    		if(ql<=l&&r<=qr)
    		{
    			setv[o]=min(setv[o],num);
    			num-=r-l+1;
    			return;
    		}
    		pushdown(o,l,r);
    		if(ql<=mid)optset(lson,l,mid,ql,qr);
    		if(qr>mid)optset(rson,mid+1,r,ql,qr);
    		return;
    	}
    	void rebuild(int o,int l,int r)
    	{
    		if(l==r)return;
    		pushdown(o,l,r);
    		rebuild(lson,l,mid);
    		rebuild(rson,mid+1,r);
    		setv[o]=inf;
    	}
    	inline void pushdown_(int o)
    	{
    		if(setv[o]==inf)return;
    		setv[lson]=min(setv[lson],setv[o]);
    		setv[rson]=min(setv[rson],setv[o]);
    		setv[o]=inf;
    	}
    	void optset_(int o,int l,int r,int ql,int qr)
    	{
    		if(ql<=l&&r<=qr)
    		{
    			setv[o]=min(setv[o],num);
    			return;
    		}
    		pushdown_(o);
    		if(ql<=mid)optset_(lson,l,mid,ql,qr);
    		if(qr>mid)optset_(rson,mid+1,r,ql,qr);
    		return;
    	}
    	void print(int o,int l,int r)
    	{
    		if(l==r)
    		{
    			printf("%d
    ",setv[o]);
    			return;
    		}
    		pushdown_(o);
    		print(lson,l,mid);
    		print(rson,mid+1,r);
    	}
    }T;
    int main()
    {
    	int n;
    	scanf("%s",ch);n=strlen(ch);
    	for(int i=0;i<n;i++)insert(ch[i]-'a'),id[last]=i;
    	T.build(1,0,n-1);
    	for(int x=1;x<=size;x++)flag[s[x].link]=true;
    	for(int x=1;x<=size;x++)if(!flag[x])
    	{
    		int l=id[x]-s[x].len+1;
    		int r=id[x]-s[s[x].link].len;
    		T.num=s[x].len;
    		T.optset(1,0,n-1,l,r);
    	}
    	T.rebuild(1,0,n-1);
    	for(int x=1;x<=size;x++)if(!flag[x])
    	{
    		int l=id[x]-s[s[x].link].len+1;
    		int r=id[x];
    		T.num=s[s[x].link].len+1;
    		T.optset_(1,0,n-1,l,r);
    	}
    	T.print(1,0,n-1);
    	return 0;
    }
    
  • 相关阅读:
    面向连接的网络应用程序--服务器端
    使用完整读写函数的网络应用程序
    套接字编程基础
    网络编程基础
    传输控制协议TCP
    UDP协议
    电子词典
    strtok()函数、fseek()函数、fwrite()函数、fread()函数的使用
    指针与数组
    软件推荐----RDO(Remote Desktop Organizer)
  • 原文地址:https://www.cnblogs.com/Creed-qwq/p/10149036.html
Copyright © 2011-2022 走看看