• 8.10 NOI模拟赛 fzhtql SAM 后缀数组 启发式合并 dsu on tree 树状数组 set 线段树合并


    LINK:fzhtql

    avatar
    avatar

    大概也就是这样一道题.

    思维难度中等. 码力要求比较高.

    大概就是 感觉很不好做 先考虑长度问题.

    需要暴力扫每个本质不同的串来check.

    长度没有单调性 也不容易二分.

    这是和right集有关的 不妨利用线段树合并把right集先抽出来.

    然后是一个和长度有关的问题 可以这样想 总长度-重合部分.

    重合部分我们也需要暴力扫 设 当前长度为len 距离为D 那么重合部分为 max(len-D,0).

    这样 写一个主席树就可以维护这个关系了.check就是logn的

    不过此时复杂度还是不太对 因为要对所有本质不同的串进行check.

    实际上我们在某个节点处check的是 l1-dl2之间的串 考虑其中一个mid是合法的 那么其他长度必然不合法.

    证明可以画一下图 这样我们就可以在节点处进行二分来确定长度了.

    最后是字典序的问题 暴力比对复杂度还是不对.

    考虑上后缀数组 ST求LCP 来比对字典序 复杂度就对了.

    第一步 怎么维护那个关系 一种容易想到的做法是set维护right集 主席树维护D.

    set进行启发式合并 主席树进行线段树合并即可.

    不过这样常数有点大 考虑把主席树变成树状数组也好写一点.

    这样 我们不能树状数组合并. 所以考虑进行dsu on tree.

    用一个全局树状数组来解决问题. 进行dsu on tree之后 set就不需要启发式合并了.

    一个全局set就可以维护right了.

    复杂度是nlog^2的 跑的还算挺快的.

    code
    //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<ctime>
    #include<cctype>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<ctime>
    #include<cmath>
    #include<cctype>
    #include<cstdlib>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<algorithm>
    #include<utility>
    #include<bitset>
    #include<set>
    #include<map>
    #define ll long long
    #define db double
    #define INF 1000000000
    #define inf 1000000000000000ll
    #define ldb long double
    #define pb push_back
    #define put_(x) printf("%d ",x);
    #define get(x) x=read()
    #define gt(x) scanf("%d",&x)
    #define gi(x) scanf("%lf",&x)
    #define put(x) printf("%d
    ",x)
    #define putl(x) printf("%lld
    ",x)
    #define rep(p,n,i) for(RE int i=p;i<=n;++i)
    #define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
    #define fep(n,p,i) for(RE int i=n;i>=p;--i)
    #define vep(p,n,i) for(RE int i=p;i<n;++i)
    #define pii pair<int,int>
    #define mk make_pair
    #define RE register
    #define P 13331ll
    #define gf(x) scanf("%lf",&x)
    #define pf(x) ((x)*(x))
    #define uint unsigned long long
    #define ui unsigned
    #define EPS 1e-5
    #define sq sqrt
    #define S second
    #define F first
    #define mod 1000000007
    #define md 998244353
    #define max(x,y) ((x)<(y)?y:x)
    #define f(i) t[i].fa
    #define len(i) t[i].len
    #define zz p<<1
    #define yy p<<1|1
    #define in insert
    #define er erase
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
    	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
    	RE int x=0,f=1;RE char ch=getc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
    	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
    	return x*f;
    }
    const int MAXN=100010;
    int TT,n,m,k,cnt=1,last=1,len;
    char a[MAXN];
    int c[MAXN],sz[MAXN],son[MAXN],lcp[MAXN],x[MAXN],y[MAXN<<1],sa[MAXN],rk[MAXN];
    int g[MAXN][20],Log[MAXN],lin[MAXN<<1],ver[MAXN<<1],nex[MAXN<<1],pos[MAXN<<1];
    set<int>s;
    set<int>::iterator it,it1;
    pii ans;
    struct wy
    {
    	int fa,len;
    	int ch[26];
    }t[MAXN<<1];
    inline void cle()
    {
    	rep(1,cnt,i)t[i]=t[0],pos[i]=0;
    	cnt=last=1;
    	//memset(c,0,sizeof(c));
    	//memset(sa,0,sizeof(sa));
    	//memset(g,0,sizeof(g));
    	memset(y,0,sizeof(y));
    	//memset(x,0,sizeof(x));
    	//s.clear();
    	//ans.F=INF;
    	//memset(rk,0,sizeof(rk));
    	
    	//memset(a,0,sizeof(a));
    	//memset(lin,0,sizeof(lin));
    }
    inline void add(int x,int y)
    {
    	ver[++len]=y;
    	nex[len]=lin[x];
    	lin[x]=len;
    }
    
    struct jl
    {
    	int c[MAXN],s[MAXN];
    	inline void add(int x,int y,int z)
    	{
    		while(x<=n)c[x]+=y,s[x]+=z,x+=x&(-x);
    		return;
    	}
    	inline pii ask(int x)
    	{
    		int cnt=0,cnt1=0;
    		while(x)cnt+=c[x],cnt1+=s[x],x-=x&(-x);
    		return mk(cnt,cnt1);
    	}
    }T;
    inline void SA()
    {
    	m=150;
    	rep(1,m,i)c[i]=0;
    	rep(1,n,i)++c[x[i]=a[i]];
    	rep(2,m,i)c[i]+=c[i-1];
    	rep(1,n,i)sa[c[x[i]]--]=i;
    	for(int k=1;k<=n;k=k<<1)
    	{
    		int num=0;
    		rep(n-k+1,n,i)y[++num]=i;
    		rep(1,n,i)if(sa[i]>k)y[++num]=sa[i]-k;
    		rep(1,m,i)c[i]=0;
    		rep(1,n,i)++c[x[i]];
    		rep(2,m,i)c[i]+=c[i-1];
    		fep(n,1,i)sa[c[x[y[i]]]--]=y[i];
    		rep(1,n,i)y[i]=x[i],x[i]=0;
    		x[sa[1]]=num=1;
    		rep(2,n,i)x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
    		if(num==n)break;
    		m=num;
    	}
    }
    inline void get_LCP()
    {
    	rep(1,n,i)rk[sa[i]]=i;
    	int k=0;
    	rep(1,n,i)
    	{
    		if(rk[i]==1)
    		{
    			g[rk[i]][0]=lcp[rk[i]]=0;
    			continue;
    		}
    		if(k)--k;
    		int j=sa[rk[i]-1];
    		while(j+k<=n&&i+k<=n&&a[i+k]==a[j+k])++k;
    		g[rk[i]][0]=lcp[rk[i]]=k;
    	}
    }
    inline void insert(int x)
    {
    	int p=last;
    	int np=last=++cnt;
    	len(np)=len(p)+1;
    	while(p&&!t[p].ch[x])
    	{
    		t[p].ch[x]=np;
    		p=f(p);
    	}
    	if(!p)f(np)=1;
    	else
    	{
    		int q=t[p].ch[x];
    		if(len(q)==len(p)+1)f(np)=q;
    		else
    		{
    			int nq=++cnt;
    			t[nq]=t[q];
    			len(nq)=len(p)+1;
    			f(q)=f(np)=nq;
    			while(p&&t[p].ch[x]==q)
    			{
    				t[p].ch[x]=nq;
    				p=f(p);
    			}
    		}
    	}
    }
    inline int LCP(int x,int y)
    {
    	if(x==y)return INF;
    	x=rk[x];y=rk[y];
    	if(x>y)swap(x,y);
    	++x;int z=Log[y-x+1];
    	return min(g[x][z],g[y-(1<<z)+1][z]);
    }
    inline void gx(pii w)
    {
    	if(w.F>ans.F)return;
    	if(w.F<ans.F){ans=w;return;}
    	int ww=LCP(ans.S,w.S);
    	if(ww>=ans.F)return;
    	if(a[ans.S+ww]<a[w.S+ww])return;
    	ans=w;return;
    }
    inline void dfs(int x)
    {
    	sz[x]=1;son[x]=0;
    	go(x)
    	{
    		dfs(tn);
    		sz[x]+=sz[tn];
    		if(sz[son[x]]<sz[tn])son[x]=tn;
    	}
    }
    inline void add(int x)
    {
    	s.in(x);
    	if(s.size()==1)return;
    	it=s.find(x);
    	it1=it;++it1;
    	if(it!=s.begin()&&it1!=s.end())
    	{
    		--it;
    		T.add(*it1-*it,-*it1+*it,-1);
    		T.add(x-*it,x-*it,1);
    		T.add(*it1-x,*it1-x,1);
    		return;
    	}
    	if(it1!=s.end())
    	{
    		T.add(*it1-x,*it1-x,1);
    		return;
    	}
    	--it;T.add(x-*it,x-*it,1);
    }
    inline void del(int x)
    {
    	it=s.find(x);
    	if(s.size()==1){s.er(it);return;}
    	it1=it;++it1;
    	if(it!=s.begin()&&it1!=s.end())
    	{
    		--it;
    		T.add(*it1-*it,*it1-*it,1);
    		T.add(x-*it,-x+*it,-1);
    		T.add(*it1-x,-*it1+x,-1);
    		s.er(x);return;
    	}
    	if(it1!=s.end())
    	{
    		T.add(*it1-x,-*it1+x,-1);
    		s.er(x);return;
    	}
    	--it;T.add(x-*it,-x+*it,-1);
    	s.er(x);
    }
    inline void calc(int x,int op)
    {
    	if(pos[x]){if(op==1)add(pos[x]);else del(pos[x]);}
    	go(x)calc(tn,op);
    }
    inline int ask(int x)
    {
    	pii w=T.ask(x);
    	ll cc=(ll)x*(s.size()-w.S)+w.F;
    	if(cc==k)return 0;
    	if(cc>k)return 1;
    	return -1;
    }
    inline void dp(int x,int op)
    {
    	//if(pos[x]==8)cout<<"ww"<<endl;
    	go(x)if(tn!=son[x])dp(tn,0);
    	if(son[x])dp(son[x],1);
    	go(x)if(tn!=son[x])calc(tn,1);
    	if(pos[x])add(pos[x]);
    	int l=len(f(x))+1,r=min(ans.F,len(x));
    	if(l<=r)
    	{
    		//if(pos[x]==8)for(it=s.begin();it!=s.end();++it)put(*it);
    		while(l<r)
    		{
    			int mid=(l+r)>>1;
    			if(ask(mid)<0)l=mid+1;
    			else r=mid;
    		}
    		if(ask(r)==0)gx(mk(r,*s.begin()-r+1));
    	}
    	if(!op)calc(x,0);
    }
    int main()
    {
    	freopen("fzhtql.in","r",stdin);
        freopen("fzhtql.out","w",stdout);
    	scanf("%d",&TT);
    	rep(2,100000,i)Log[i]=Log[i>>1]+1;
    	while(TT--)
    	{
    		cle();len=0;ans.F=INF;
    		
    		scanf("%s",a+1);scanf("%d",&k);
    		
    		n=strlen(a+1);
    		
    		SA();get_LCP();
    		
    		//put(LCP(1,5));
    		
    		rep(1,Log[n],j)rep(1,n-(1<<j),i)g[i][j]=min(g[i+(1<<(j-1))][j-1],g[i][j-1]);
    		
    		rep(1,n,i)insert(a[i]-'a'),pos[last]=i;
    		
    		rep(1,cnt,i)lin[i]=0;
    
    		rep(2,cnt,i)add(f(i),i);
    		
    		dfs(1);
    		
    		dp(1,0);
    		
    		//put(ans.F);
    		
    		if(ans.F==INF)puts("NOTFOUND!");
    		else 
    		{
    			rep(ans.S,ans.S+ans.F-1,i)printf("%c",a[i]);
    			puts("");
    		}
    	}
    	return 0;
    }
    

    大概是算是又复习了一遍板子 难写是真的难写.

  • 相关阅读:
    Spark Streaming源码解读之Receiver生成全生命周期彻底研究和思考
    linux 修改时间时区,修改语言
    远程链接mysql error 2003
    Android NDK r10c 编译boost 1.55 (使用Cygwin)
    linux上cocos2dx Android打包环境
    linux上cocos2dx 环境配置
    linux, windows编译安装 boost库 (boost 1.56)
    编译安装 gcc 4.8.3
    vim配置添加python
    mvn设置
  • 原文地址:https://www.cnblogs.com/chdy/p/13473687.html
Copyright © 2020-2023  润新知