首页 > 其他分享 >Loj #6041. 「雅礼集训 2017 Day7」事情的相似度

Loj #6041. 「雅礼集训 2017 Day7」事情的相似度

时间:2023-06-13 22:57:08浏览次数:48  
标签:ch links 雅礼 Loj Day7 tr len int 后缀

做到这题,发现自己对\(SAM\)的一些性质还不知道,特此记录。
题目要求01字符串区间内前缀的最长公共后缀
由SAM parent tree性质可知,2个前缀的最长公共后缀就是它们在parent tree上lca的len值
如何去感性理解
我们知道,在parent tree上每个节点都代表了一个endpos等价类,由后缀链接将他们连接起来,并且从根顺着向上走其实是一个不断从开头删去字符的过程,佐张图以供理解:
image

如果我们将一个前缀不停删去它的前缀(其实就是跳它的后缀)的过程看作是在parent tree上向根跳跃,并在所经历的节点上打上标记,那么,当另一个前缀也重复上述过程时,碰到的第一个有标记的节点的len,即为两前缀的最长公共后缀

前缀最长公共前缀解决了,现在我们想想如何维护这个跳后缀的过程。
发现这其实是一个根到目标节点的链覆盖,发现重链剖分并不能很好维护标记。
考虑实链剖分,联想到LCT的access操作:将根到u的路径变为一条实链。
正是我们需要的链覆盖(可脑补一下过程
LCT上只需要维护一下颜色覆盖和标记即可(根不变甚至不需要反转,pushup,link,cut

现在我们还有最后一个棘手的要求:区间
既然可以离线,考虑扫描线,将询问挂在右端点上。
先将SAM建好,明确parent tree的形态,从左至右加入前缀。
每次access时查看最近一次访问此节点的标记,并以此标记(不是自己),在任意一个可维护区间最大值的数据结构上更新区间后缀最大值。
然后贪心的覆盖上自己的标。
查询即在处理完R后询问维护的 \(L-N\) 的后缀最大值即可。
关于为什么直接覆盖,可以想到,每次是查询区间后缀最大值,端点越靠右,能影响更新到的区间就越多。
代码细节实现如下:

点击查看代码
#include<bits/stdc++.h>
using namespace std;
inline int rd(void){
	char ch=getchar();int f=1,res=0;
	while(!isdigit(ch)){
		if(ch=='-')f=0;
		ch=getchar();
	}
	while(isdigit(ch)){
		res=res*10+(ch-'0');
		ch=getchar();
	}
	return f?res:-res;
}
const int N=4e5+10;
int ch[N][2],links[N],len[N],tot=1,pos[N];
int last=1,tr[N][2],n,m;
void sam_extend(int x,int id){
	int cur=++tot;
	len[cur]=len[last]+1;
	pos[id]=tot;
	int p=last;
	while(p&&tr[p][x]==0){
		tr[p][x]=cur;
		p=links[p];
	}
	if(p==0){
		links[cur]=1;
	}else{
		int q=tr[p][x];
		if(len[p]+1==len[q]){
			links[cur]=q;
		}
		else{
			int cl=++tot;
			memcpy(tr[cl],tr[q],sizeof(tr[q]));
			links[cl]=links[q];
			len[cl]=len[p]+1;
			while(p&&tr[p][x]==q){
				tr[p][x]=cl;
				p=links[p];
			}
			links[q]=links[cur]=cl;
		}
	}
	last=cur;
}
int f[N];
struct BIT{
	int t[N];
	inline int lowbit(int x){return x&(-x);}
	void upd(int x,int v){
		x=n-x+1;
		while(x<=n){
			t[x]=max(t[x],v);
			x+=lowbit(x);
		}
	} 
	inline int query(int x){
		int res=0;
		x=n-x+1;
		while(x){
			res=max(res,t[x]);
			x-=lowbit(x);
		}
		return res;
	}
}bit;
inline int nrt(int x){
	return (ch[f[x]][0]==x||ch[f[x]][1]==x);
}
inline int son(int x){
	return x==ch[f[x]][1];
}
void rotate(int x){
	int y=f[x],z=f[y];
	int kx=son(x),ky=son(y),w=ch[x][kx^1];
	if(nrt(y))ch[z][ky]=x;
	ch[x][kx^1]=y;
	ch[y][kx]=w;
	f[x]=z;f[y]=x;
	if(w)f[w]=y;
}
int tg[N],col[N];	
void change(int x,int v){
	tg[x]=col[x]=v;
}
void pd(int x){
	if(!tg[x])return ;
	if(ch[x][0])change(ch[x][0],tg[x]);
	if(ch[x][1])change(ch[x][1],tg[x]);
	tg[x]=0;
}
int sta[N];
void splay(int x){
	int now=x,top=0;
	sta[++top]=x;
	while(nrt(now))sta[++top]=now=f[now];
	while(top)pd(sta[top--]);
	while(nrt(x)){
		int y=f[x],z=f[y];
		if(nrt(y))
			(son(y)^son(x))?rotate(x):rotate(y);
		rotate(x);
	}
}
void access(int x,int v){
	int pre;
	for(pre=0;x;x=f[pre=x]){
		splay(x);
		bit.upd(col[x],len[x]);
		ch[x][1]=pre;
	}
	splay(pre);
	change(pre,v);
}
char s[N];
int ans[N];
#define pii pair<int,int>
vector<pii> G[N];
int main(){
	n=rd();m=rd();scanf("%s",s+1);
	for(int i=1;i<=n;i++)sam_extend(s[i]-'0',i);
	for(int i=1,l,r;i<=m;i++){
		l=rd();r=rd();
		G[r].push_back({l,i});
	}
	for(int i=2;i<=tot;i++){
		f[i]=links[i];
		//printf("* %d\n",len[i]);
		//printf("%d %d\n",links[i],i);
	}		
	for(int i=1;i<=n;i++){
		access(pos[i],i);
		for(pii j:G[i]){
			ans[j.second]=bit.query(j.first);	
		}
	}
	for(int i=1;i<=m;i++){
		printf("%d\n",ans[i]);
	}
	return 0;
}

标签:ch,links,雅礼,Loj,Day7,tr,len,int,后缀
From: https://www.cnblogs.com/Linnyx/p/17478887.html

相关文章

  • nginx-clojure debug构建简单说明
    实际上参考了官方的构建参数,提供一个debug模式的文件原始配置configurearguments:--prefix=--sbin-path=nginx--conf-path=conf/nginx.conf--error-log-path=logs/error.log--http-log-path=logs/access.log--pid-path=logs/nginx.pid--lock-path=logs/nginx.......
  • nginx-clojure-0.6.0 集成nginx 1.25.0 构建的解决方法
    今天也说过关于nginx-clojure-0.6.0集成nginx1.2.50构建是有问题的,以下是解决方法实际问题staticdeclarationof‘ngx_http_close_request’followsnon-staticdeclaration原因nginx-clojure复制了nginx源码中对于nginx的处理函数(ngx_http_clojure_mem.c文件)......
  • nginx-clojure 源码构建一些问题
    因为nginx-clojure就是一个标准的nginx模块,一些是尝试基于源码进行构建发现一些问题的说明简单说明nginx当前1.25版本的构建是有问题的,1.24版本构建是可以的,1.23版本实际上官方已经提供了但是如果查看nginx官方文档会发现1.23版本的下载官方是似乎移除了,没直接提......
  • nginx-clojure 0.6.0 的一些新特性
    昨天制作了0.6.0的docker镜像,并说明了一些问题,以下简单说明下一些新特性新特性所有的handler可以在http以及servercontext使用了,可以方便进行组合使用nginx1.23.x支持jdk19支持,支持协程了官方提供的二进制构建基于1.23.3说明昨天也说明了,官方提供的二进制包缺......
  • loj6039. 「雅礼集训 2017 Day5」珠宝
    题目大意有\(n\)个物品,第\(i\)个费用为\(w_i\),价值为\(v_i\),对于\(k\in[1,m]\)求费用为\(m\)时能获得的最大价值。\(1\leqn\leq10^6,1\leqm\leq5\times10^4,1\leqw_i\leq300,1\leqv_i\leq10^9\)思路\(n\)很大,但\(w_i\)很小,于是我们考虑以其为突破口......
  • 小灰灰深度学习day7——画一元二次方程某一点的切线以及一些概念
    #我们在这里画的是方程3*x**2-4*x在x=1处的切线#欠拟合:欠拟合指的是模型对训练数据的拟合度过低,误差值过大,自然泛化能力也不怎么好。#泛化能力指模型对未知数据的拟合度#过拟合:指模型对训练数据的拟合度较好,误差值较小,但是泛化能力并不好。#对误差函数进行惩罚,从......
  • 软件测试day7
    正交实验法:用最少的用例,覆盖最多的路径黑盒测试用例方法(后半补全)如何设计测试用例  (在工作中不要自己想期望结果,看文档所列来决定) 测试用例规范 ......
  • 【loj3396】novel(AC自动机维护文本串子串的匹配信息)
    设当前询问的串为\(s_i\)记为\(t\)。考虑\(r\)右移,维护每个\(l\)对应的\(g(l,r)\)和\(\max_{l}\frac{g(l,r)}{r-l+1}\)即可。最基本的观察是:当\(r\)右移后,考虑\(t_{1..r}\)在AC自动机上匹配到的点\(p\),那么对于\(p\)的任意祖先(包含\(p\))\(u\),都会给\(l\leq......
  • 「LOJ3405」Gem Island 2
    题目点这里看题目。有一个长度为\(n\)的序列\(a_1,a_2,\dots,a_n\)。初始时,\(\forall1\lei\len,a_i=1\)。接下来进行\(d\)轮操作。每一轮操作会以\(\frac{a_i}{\sum_{j=1}^na_j}\)的概率选出\(i\)并令\(a_i\getsa_i+1\)。求\(d\)轮操作后,\(a\)的前\(r\)大......
  • day79(2023.5.27)
    1.Ajax技术详解Ajax简介 2.Ajax的使用3.Ajax请求4.JSON详解5.JACKSON的使用6.常用注解7.Jquery的Ajax使用8.Ajax实战创建项目创建Java项目......