CF 666E 题解

89 篇文章 1 订阅

CF666E 题解

首先可以将所有的串用无关字符连接起来:s[1]+’#’+s[2]+’#’…s[n]

然后建一个SAM。

在每一个节点上搞一个动态开点线段树。

然后从下往上线段树合并。

最后像最长公共子串那样跑一边,倍增找到节点就可以了。

/*
{
######################
#       Author       #
#        Gary        #
#        2020        #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
//inline int read(){
//    int x=0;
//    char ch=getchar();
//    while(ch<'0'||ch>'9'){
//        ch=getchar();
//    }
//    while(ch>='0'&&ch<='9'){
//        x=(x<<1)+(x<<3)+(ch^48);
//        ch=getchar();
//    }
//    return x;
//}
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXLEN=1e6+20;
struct state{
	int len,link,minlen,rt;
	unordered_map<char,int> ch;
};
int cnt=0;
vector<int> l(1,0),r(1,0);
vector<mp> ret(1,II(0,0));
mp get(mp A,mp B){
	if(A.SEC!=B.SEC){
		if(A.SEC<B.SEC) return B;
		return A;
	}
	return min(A,B);
}
int newnodes(){
	cnt++;
	ret.PB(II(0,0));
	l.PB(0);
	r.PB(0);
	return cnt;
}
const int N=1<<16;
void add(int now,int pos,int L=1,int R=N+1){
	if(L>pos||R<=pos) return;
	if(L==R-1){
		ret[now].FIR=L;
		ret[now].SEC++;
		return ;
	}
	int mid=(L+R)>>1;
	if(!l[now]){
		l[now]=newnodes();
		r[now]=newnodes();
	}
	add(l[now],pos,L,mid);
	add(r[now],pos,mid,R);
	ret[now]=get(ret[l[now]],ret[r[now]]);
}
int merge(int A,int B,int L=1,int R=N+1){
	if(A==0||B==0){
		return A+B;	
	}
	if(L==R-1){
		newnodes();
		ret[cnt].FIR=L;
		ret[cnt].SEC=ret[A].SEC+ret[B].SEC; 
		return cnt;
	}
	newnodes();
	int now=cnt;
	int mid=(L+R)>>1;
	l[now]=merge(l[A],l[B],L,mid);
	r[now]=merge(r[A],r[B],mid,R);
	ret[now]=get(ret[l[now]],ret[r[now]]);
	return now;
}
mp query(int a,int b,int now,int L=1,int R=N+1){
	if(!now) return II(0,0);
	if(R<=a||L>=b) return II(0,0);
	if(R<=b&&L>=a) {
		return ret[now];	
	}
	int mid=(L+R)>>1;
	return get(query(a,b,l[now],L,mid),query(a,b,r[now],mid,R));
}
struct SAM{	
	int sz=0,last;
	state st[MAXLEN+MAXLEN];
	bool vis[MAXLEN+MAXLEN];
	int siz[MAXLEN+MAXLEN];//出现次数 
	vector<int> g[MAXLEN+MAXLEN];
	int siz2[MAXLEN+MAXLEN];//状态大小 
	void sam_init(){
		memset(vis,0,sizeof(vis));
		st[0].len=0;
		st[0].link=-1;
		sz=0;
		st[0].rt=newnodes();
		last=0;
	}
	SAM(){
		sam_init();
	}
	void sam_extend(char c,int id){
		int cur=++sz;
		st[cur].rt=newnodes();
		st[cur].len=st[last].len+1;
		int p=last;
		while(p!=-1&&st[p].ch.find(c)==st[p].ch.end()){
			st[p].ch[c]=cur;
			p=st[p].link;
		} 
		if(p==-1){
			st[cur].link=0;
		}
		else{
			int q=st[p].ch[c];
			if(st[q].len==st[p].len+1){
				st[cur].link=q;
			}
			else{
				int clone;
				clone=++sz;
				st[clone].rt=newnodes();
				st[clone].len=st[p].len+1;
				st[clone].ch=st[q].ch;
				st[clone].link=st[q].link;
				while(p!=-1&&st[p].ch.find(c)!=st[p].ch.end()&&st[p].ch[c]==q){
					st[p].ch[c]=clone;
					p=st[p].link;
				}
				st[cur].link=st[q].link=clone;
			}
		}
		last=cur;
		siz[cur]++;
		add(st[cur].rt,id);
	}
	void dfs(int now){
		vis[now]=true;
		for(auto it:g[now]){
			if(!vis[it]) dfs(it);
			siz[now]+=siz[it];
		}
	}
	void dfs2(int now){
		vis[now]=1;
		for(auto it:g[now]){
			if(!vis[it]) dfs2(it);
			siz2[now]+=siz2[it];
		}
	}
	void dfs3(int now){
		for(auto it:g[now]){
			dfs3(it);
			st[now].rt=merge(st[now].rt,st[it].rt);
//			cout<<now<<' '<<it<<' '<<' '<<ret[st[it].rt].FIR<<' '<<ret[st[it].rt].SEC<<")("<<ret[st[now].rt].SEC<<' '<<ret[st[now].rt].SEC<<endl;
		}
	}
	void run(){
		rb(i,1,sz) g[st[i].link].PB(i);
		rb(i,0,sz) if(!vis[i]) dfs(i);
		dfs3(0);
		rb(i,0,sz) g[i].clear();
		memset(vis,0,sizeof(vis));
		siz2[0]=1;
		rb(i,0,sz) for(auto ite=st[i].ch.begin();ite!=st[i].ch.end();ite++) g[ite->SEC].PB(i);
		rb(i,0,sz) if(!vis[i]) dfs2(i);
		rb(i,1,sz) st[i].minlen=st[i].len-siz2[i]+1;
	}
}sam;
int stay[500000+10];
int le[500000+10];
int bz[MAXLEN+MAXLEN][20];
int main(){
	//--------------------
//	int A=newnodes(),B=newnodes();
//	add(A,1);
//	add(B,1);
//	A=merge(A,B);
//	cout<<ret[A].SEC<<endl;
//	return 0;
	//--------------------
	string s;
	cin>>s;
	int m;
	cin>>m;
	rb(i,1,m){
		string t;
		cin>>t;
		sam.sam_extend('#',m+1);
		rep(j,t.length()){
			sam.sam_extend(t[j],i);
		}
	}
	sam.run();
//	cout<<sam.st[0].rt<<' '<<ret[sam.st[0].rt].SEC<<endl;
	int leng=s.length();
	int now=0,len=0;
	rb(i,1,leng){
		while(now!=-1&&sam.st[now].ch.find(s[i-1])==sam.st[now].ch.end()){
			now=sam.st[now].link;
			len=sam.st[now].len;
		}
		if(now==-1){
			now=0;
			len=0;
		}
		else{
			now=sam.st[now].ch[s[i-1]];
			len++;
		}
		stay[i]=now;
		le[i]=len;
	}
	rb(i,1,sam.sz){
		bz[i][0]=sam.st[i].link;
	}
	rb(j,1,19){
		rb(i,1,sam.sz){
			bz[i][j]=bz[bz[i][j-1]][j-1];		
		}
	}
	int q;
	scanf("%d",&q);
	rb(i,1,q){
		int l,r,pl,pr;
		scanf("%d%d%d%d",&l,&r,&pl,&pr);
		pl=pr-pl+1;
		if(le[pr]<pl){
			printf("%d 0\n",l);	
			continue;
		}
		int now=stay[pr];
		rl(i,19,0){
			if(sam.st[bz[now][i]].len>=pl){
				now=bz[now][i];
			}
		}
		now=sam.st[now].rt;
		mp rest=query(l,r+1,now);
		if(rest.SEC==0) rest.FIR=l;
		printf("%d %d\n",rest.FIR,rest.SEC);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值