• P7046-「MCOI-03」诗韵【SAM,倍增,树状数组】


    正题

    题目链接:https://www.luogu.com.cn/problem/P7046


    题目大意

    给出一个长度为 (n) 的字符串,然后 (m) 次把它的一个子串加入集合。如果一个字符串在这个集合中作为字符串的后缀出现次数大于 (k) 那么这个字符串就会被计入贡献。
    每次求计入贡献的字符串数和最长长度。

    (1leq n,mleq 5 imes 10^5,0leq k<n)


    解题思路

    考虑在parents树上如果能定位到一个节点的字符串那么它的后缀就是它到根的路径。

    但是可能定位不到根,一种暴力的做法是每条边上建一个线段树然后暴力改。但是这样很麻烦可以考虑让每个询问一定能定位到一个节点。

    我们直接建好树然后每次把询问倍增挂到对应的边上用set储存,然后再重新建一棵包含每个节点的树。

    那么现在问题就变为了统计子树权值大于 (k) 的节点了,因为每个点到根的路径上满足条件的边一定是一段后缀,而每个节点最多统计一次,所以我们直接每次倍增找到最上面的没有统计的节点用树状数组+(dfs) 序判断是否合法就好了。

    时间复杂度:(O(nlog n))(默认 (n,m) 同级)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<set>
    #define lowbit(x) (x&-x)
    using namespace std;
    const int M=1e6+10,N=2e6+10,T=21;
    struct node{
    	int to,next;
    }a[N];
    int n,m,k,last,cnt,tot,ans2;long long ans1;
    int ch[M][26],len[N],fa[N],L[M],R[M],p[M],las[M];
    int ls[N],v[N],pos[N],f[N][T],rfn[N],ed[N],dos[M];
    set<int> ct[M];vector<int> q[M];char s[M];
    set<int>::iterator it;
    void Insert(int c){
    	int p=last,np=last=++cnt;len[np]=len[p]+1;
    	for(;p&&!ch[p][c];p=fa[p])ch[p][c]=np;
    	if(!p)fa[np]=1;
    	else{
    		int q=ch[p][c];
    		if(len[q]==len[p]+1)fa[np]=q;
    		else{
    			int nq=++cnt;len[nq]=len[p]+1;
    			memcpy(ch[nq],ch[q],sizeof(ch[nq]));
    			fa[nq]=fa[q];fa[q]=fa[np]=nq;
    			for(;p&&ch[p][c]==q;p=fa[p])ch[p][c]=nq;
    		}
    	}
    	return;
    }
    void work(int p,int l,int r){
    	int x=pos[r];
    	for(int i=T-1;i>=0;i--)
    		if(len[f[x][i]]>=r-l+1)x=f[x][i];
    	if(ct[x].count(r-l+1))return;
    	ct[x].insert(r-l+1);q[x].push_back(p);
    	return;
    }
    void addl(int x,int y){
    	a[++tot].to=y;
    	a[tot].next=ls[x];
    	ls[x]=tot;return;
    }
    bool cmp(int x,int y)
    {return R[x]-L[x]+1<R[y]-L[y]+1;}
    bool cMp(int x,int y)
    {return len[x]<len[y];}
    void dfs(int x){
    	rfn[x]=++cnt;
    	for(int i=ls[x];i;i=a[i].next){
    		int y=a[i].to;
    		f[y][0]=x;dfs(a[i].to);
    	}
    	ed[x]=cnt;return;
    }
    struct TreeBinary{
    	int t[N];
    	void Change(int x,int val){
    		while(x<=n){
    			t[x]+=val;
    			x+=lowbit(x);
    		}
    		return;
    	}
    	int Ask(int x){
    		int ans=0;
    		while(x){
    			ans+=t[x];
    			x-=lowbit(x);
    		}
    		return ans;
    	}
    }B;
    int main()
    {
    	scanf("%d%d%d",&n,&m,&k);
    	scanf("%s",s+1);cnt=last=1;
    	for(int i=1;i<=n;i++)Insert(s[i]-'a'),pos[i]=last;
    	for(int i=1;i<=cnt;i++)f[i][0]=fa[i];
    	for(int j=1;j<T;j++)
    		for(int i=1;i<=cnt;i++)
    			f[i][j]=f[f[i][j-1]][j-1];
    	for(int i=1;i<=m;i++){
    		scanf("%d%d",&L[i],&R[i]);
    		work(i,L[i],R[i]);
    	}
    	for(int i=1;i<=cnt;i++)p[i]=i,ct[i].insert(len[i]);
    	sort(p+1,p+1+cnt,cMp);
    	int pnt=cnt;cnt=1;las[1]=1;
    	for(int i=2;i<=pnt;i++){
    		int x=p[i];
    		sort(q[x].begin(),q[x].end(),cmp);
    		int z=0;las[x]=las[fa[x]];
    		it=ct[x].begin();
    		while(1){
    			++cnt;addl(las[x],cnt);las[x]=cnt;
    			int W=*it;len[cnt]=*it;
    			while(z<q[x].size()&&R[q[x][z]]-L[q[x][z]]+1<=W)
    				dos[q[x][z]]=cnt,z++;
    			it++;if(it==ct[x].end())break;
    		}
    	}
    	n=cnt;cnt=0;dfs(1);v[0]=1;len[0]=-1;
    	for(int j=1;j<T;j++)
    		for(int i=1;i<=n;i++)
    			f[i][j]=f[f[i][j-1]][j-1];
    	for(int i=1;i<=m;i++){
    		int p=dos[i];
    		if(!p){printf("%lld %d
    ",ans1,ans2);continue;}
    		B.Change(rfn[p],1);
    		if(v[p]){printf("%lld %d
    ",ans1,ans2);continue;}
    		while(!v[p]){
    			int x=p;
    			for(int j=T-1;j>=0;j--)
    				if(!v[f[x][j]])x=f[x][j];
    			int w=B.Ask(ed[x])-B.Ask(rfn[x]-1);
    			if(w>k){
    				v[x]=1;
    				ans1+=len[x]-len[f[x][0]];
    				ans2=max(ans2,len[x]);
    			}
    			else break;
    		}
    		printf("%lld %d
    ",ans1,ans2);
    	}
    	return 0;
    }
    
  • 相关阅读:
    MySQL中如何使用布尔类型【转】
    你所不知道的Android Studio调试技巧【转】
    设计模式之工厂模式(factory pattern)【转】
    layuiadmin+tp5后台内容管理系统【转】
    PHPStorm怎么修改选中的背景颜色呢?【转】
    PHP保留两位小数的几种方法【转】
    jquery的css()函数同时设置多个css属性值
    Flutter text设置行间距【转】
    Flutter入门-布局Container、Padding、Align、Center【转】
    redis下载地址
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15321287.html
Copyright © 2020-2023  润新知