zoukankan      html  css  js  c++  java
  • CF666E 题解

    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
    ",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
    ",rest.FIR,rest.SEC);
    	}
    	return 0;
    }
    
  • 相关阅读:
    servlet中如何实现通过Spring实现对象的注入
    异步Socket
    JAVA NIO实现
    【Java并发】
    JAVA实现阻塞队列
    lock与synchronized比较
    线程执行顺序
    ConcurrentHashMap 1.8
    LeetCode 416 分割等和子集
    linux常用指令
  • 原文地址:https://www.cnblogs.com/gary-2005/p/14212903.html
Copyright © 2011-2022 走看看