zoukankan      html  css  js  c++  java
  • [HEOI/TJOI2016][洛谷P4094]字符串(SA+主席树)

    题面

    https://www.luogu.com.cn/problem/P4094

    题解

    前置知识:

    题目给出字符串S,每次询问给出a,b,c,d,问S[a..b]的所有子串与S[c..d]的lcp的最大值。

    考虑简化题意:S[a..b]的所有子串->S[a..b]的所有后缀,因为子串的右端点往右移肯定不会变差。

    首先预处理出后缀数组和height,以及height的ST表。再以0为下界,(min(d-c+1, b-a+1))为上界二分答案。假设当前答案A成立,需满足(exist x in[a,b-A+1]{ } s.t.{ }lcp(suf_x,suf_c) {geq} A)。而满足(lcp(suf_x,suf_c) geq A)的x的rank值是连续的一个区间(rank是后缀数组里的那个),可以二分得出这个区间的左右端点l、r。

    接下来的任务是:判断(rank[a],rank[a+1],…,rank[b-A+1])这些值里面,有没有(in [l,r])的。这个就可以使用主席树解决。

    总时间复杂度(O(n log^2n))

    代码

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define rg register
    #define In inline
    
    const int N = 1e5;
    const int TN = 2e6;
    
    In int read(){
    	int s = 0,ww = 1;
    	char ch = getchar();
    	while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
    	while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
    	return s * ww;
    }
    
    In void write(int x){
    	if(x < 0)putchar('-'),x = -x;
    	if(x > 9)write(x / 10);
    	putchar('0' + x % 10);
    }
    
    int n,m;
    char s[N+5];
    int lg[N+5];
    
    struct CMTree{
    	int rt[N+5],lc[TN+5],rc[TN+5],num[TN+5];
    	int cnt,rn;
    	In void pushup(int u){
    		num[u] = num[lc[u]] + num[rc[u]];
    	}
    	void ud(int u1,int u2,int l,int r,int d){
    		if(l == r){
    			num[u2]++;
    			return;
    		}	
    		int m = (l + r) >> 1;
    		if(d <= m){
    			int v = ++cnt;
    			lc[u2] = v,rc[u2] = rc[u1];
    			ud(lc[u1],lc[u2],l,m,d);
    		}
    		else{
    			int v = ++cnt;
    			rc[u2] = v,lc[u2] = lc[u1];
    			ud(rc[u1],rc[u2],m + 1,r,d);
    		}
    		pushup(u2);
    	}
    	int query(int u1,int u2,int l,int r,int ql,int qr){
    		if(l == ql && r == qr)return num[u2] - num[u1];
    		int m = (l + r) >> 1;
    		if(qr <= m)return query(lc[u1],lc[u2],l,m,ql,qr);
    		else if(ql > m)return query(rc[u1],rc[u2],m + 1,r,ql,qr);
    		else return query(lc[u1],lc[u2],l,m,ql,m) + query(rc[u1],rc[u2],m + 1,r,m + 1,qr);
    	}
    	void insert(int x){
    		rt[++rn] = ++cnt;
    		ud(rt[rn-1],rt[rn],0,n,x);
    	}
    	int sum(int a,int b,int ql,int qr){
    		return query(rt[a-1],rt[b],0,n,ql,qr);
    	}
    }T;
    
    struct ST{
    	int minn[N+5][18];
    	void prepro(int a[]){
    		for(rg int i = 1;i <= n;i++)minn[i][0] = a[i];
    		for(rg int j = 1;j <= 17;j++){
    			for(rg int i = 1;i + (1<<j) - 1 <= n;i++)minn[i][j] = min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);
    		}
    	}
    	int query(int l,int r){
    		int d = lg[r-l+1];
    		return min(minn[l][d],minn[r+1-(1<<d)][d]);
    	}
    };
    
    struct SA{
    	int sa[N+5],temp[N+5],rk[N+5],h[N+5],num[N+5];
    	int m;
    	ST H;
    	void qsort(){
    		memset(num,0,sizeof(int) * (m+1));
    		for(rg int i = 1;i <= n;i++)num[rk[i]]++;
    		for(rg int i = 2;i <= m;i++)num[i] += num[i-1];
    		for(rg int i = n;i >= 1;i--)sa[num[rk[temp[i]]]--] = temp[i];
    	}
    	void calch(){
    		int k = 0;
    		for(rg int i = 1;i <= n;i++){
    			if(rk[i] == 1)h[1] = k = 0;
    			else{
    				if(k)k--;
    				int j = sa[rk[i]-1];
    				while(s[i+k] == s[j+k])k++;
    				h[rk[i]] = k;
    			}
    		}
    	}
    	void init(){
    		m = 26;
    		for(rg int i = 1;i <= n;i++)temp[i] = i,rk[i] = s[i] - 'a' + 1;
    		qsort();
    		for(rg int d = 1;d <= n;d <<= 1){
    			int cnt = 0;
    			for(rg int i = n - d + 1;i <= n;i++)temp[++cnt] = i;
    			for(rg int i = 1;i <= n;i++)if(sa[i] > d)temp[++cnt] = sa[i] - d;
    			qsort();
    			memcpy(temp,rk,sizeof(int) * (n+1));
    			cnt = rk[sa[1]] = 1;
    			for(rg int i = 2;i <= n;i++){
    				if(temp[sa[i]] != temp[sa[i-1]] || temp[sa[i]+d] != temp[sa[i-1]+d])cnt++;
    				rk[sa[i]] = cnt;
    			}
    			if(cnt == n)break;
    			m = cnt;
    		}	
    		calch();
    		H.prepro(h);
    		for(rg int i = 1;i <= n;i++)T.insert(rk[i]);
    	}
    	int lcp(int i,int j){
    		if(i == j)return n - i + 1;
    		int x = rk[i],y = rk[j];
    		if(x > y)swap(x,y);
    		return H.query(x + 1,y);
    	}
    }S;
    
    In bool check(int A,int a,int b,int c){
    	if(!A)return 1;
    	int L,R;
    	L = 1,R = S.rk[c];
    	while(L < R){
    		int mid = (L + R) >> 1;
    		if(S.lcp(S.sa[mid],c) >= A)R = mid;
    		else L = mid + 1;
    	}
    	int l = L;
    	L = S.rk[c],R = n;
    	while(L < R){
    		int mid = (L + R + 1) >> 1;
    		if(S.lcp(c,S.sa[mid]) >= A)L = mid;
    		else R = mid - 1;
    	}
    	int r = R;
    	return T.sum(a,b - A + 1,l,r);
    }
    
    int main(){
    	for(rg int i = 2;i <= N;i++)lg[i] = lg[i>>1] + 1;
    	n = read(); m = read();
    	scanf("%s",s + 1);
    	S.init();
    	while(m--){
    		int a = read(),b = read(),c = read(),d = read();
    		int L = 0,R = min(b - a + 1,d - c + 1);
    		while(L < R){
    			int mid = (L + R + 1) >> 1;
    			if(check(mid,a,b,c))L = mid;
    			else R = mid - 1;
    		}
    		write(L),putchar('
    ');
    	}
    	return 0;
    }
    

    []

  • 相关阅读:
    phpcms 的getcache()函数
    git 上配置公钥
    linux 上git安装
    mac上php的扩展yaf安装
    Linux常用指令---grep(搜索过滤)
    mac virtualbox+vagrant安装
    nginx配置location及rewrite规则重写
    mac php环境搭建
    nginx.pid丢失问题
    git操作教程详解
  • 原文地址:https://www.cnblogs.com/xh092113/p/12464521.html
Copyright © 2011-2022 走看看