zoukankan      html  css  js  c++  java
  • [bzoj4556] [Tjoi2016&Heoi2016]字符串

    翻转原串,建后缀自动机.

    然后先考虑最朴素的思路,找到d所对应的节点,然后一直往上走,并更新答案.

    发现由于有a,b的限制,更新答案需要取min,很不爽,不如二分答案.

    然后就可以转化为判定性问题,用字符串定位技术找到当前的cd对应的字符串(其实就是倍增+len判定),

    判定当前的节点是否有当前a,b范围的right集.

    要知道每个节点的right集具体是什么用dfs序建立主席树即可.

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<ctime>
    #include<string>
    #include<iomanip>
    #include<algorithm>
    #include<map>
    using namespace std;
    #define LL long long
    #define FILE "dealing"
    #define up(i,j,n) for(int i=j;i<=n;++i)
    #define db double
    #define ull unsigned long long
    #define eps 1e-10
    #define pii pair<int,int>
    int read(){
    	int x=0,f=1,ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	return f*x;
    }
    const int maxn=200200,mod=(int)(1e9+7+0.1),limit=(int)(1e6+1);
    int n,m;
    char s[maxn>>1];
    struct node{
    	int y,next;
    }e[maxn<<1];
    int len,linkk[maxn],pre[maxn],dfs_clock=0,low[maxn],r[maxn],dep[maxn],fa[maxn][26],id[maxn],zuo[maxn],val[maxn];
    void insert(int x,int y){
    	e[++len].y=y;
    	e[len].next=linkk[x];
    	linkk[x]=len;
    }
    namespace Sam{
    	int np,p,q,nq,pre[maxn],c[maxn][26],len[maxn],cnt,now,count[maxn],sa[maxn];
    	int extend(int x){
    		p=now;now=np=++cnt;len[np]=len[p]+1;
    		while(p&&!c[p][x])c[p][x]=np,p=pre[p];
    		if(!p)pre[np]=1;
    		else {
    			q=c[p][x];
    			if(len[q]==len[p]+1)pre[np]=q;
    			else {
    				len[nq=++cnt]=len[p]+1;
    				memcpy(c[nq],c[q],sizeof(c[q]));
    				pre[nq]=pre[q];
    				pre[q]=pre[np]=nq;
    				while(p&&c[p][x]==q)c[p][x]=nq,p=pre[p];
    			}
    		}
    		return np;
    	}
    	void build(){
    		now=1,cnt=1;
    		up(i,1,n)val[extend(s[i]-'a')]=i;
    		up(i,1,cnt)zuo[val[i]]=i;
    	}
    	void prepare(){
    		up(i,1,cnt)count[len[i]]++;
    		up(i,1,cnt)count[i]+=count[i-1];
    		for(int i=cnt;i>=1;i--)sa[count[len[i]]--]=i;
    		for(int i=cnt;i>=2;i--)insert(pre[sa[i]],sa[i]),insert(sa[i],pre[sa[i]]);
    	}
    };
    namespace chair_man_tree{
    	const int maxn=3000000;
    	int c[maxn][2],sum[maxn],root[maxn],n,cnt=0,L,R;
    	void updata(int x){sum[x]=sum[c[x][0]]+sum[c[x][1]];}
    	void insert(int x,int& o,int key,int l,int r){
    		if(key==0){o=x;return;}
    		o=++cnt;
    		if(l==r){
    			sum[o]=sum[x]+1;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(key>mid){
    			c[o][0]=c[x][0];
    			insert(c[x][1],c[o][1],key,mid+1,r);
    		}
    		else {
    			c[o][1]=c[x][1];
    			insert(c[x][0],c[o][0],key,l,mid);
    		}
    		updata(o);
    	}
    	void build(){
    		up(i,1,n)insert(root[i-1],root[i],r[i],1,n);
    	}
    	int query(int x,int o,int l,int r){
    		//printf("%d %d %d
    ",l,r,sum[o]-sum[x]);
    		if(l>R||r<L)return 0;
    		if(l>=L&&r<=R)return sum[o]-sum[x];
    		if(!(sum[o]-sum[x]))return 0;
    		int mid=(l+r)>>1;
    		return query(c[x][0],c[o][0],l,mid)+query(c[x][1],c[o][1],mid+1,r);
    	}
    	int Query(int l,int r,int Le,int Ri){
    		L=Le,R=Ri;
    		//cout<<L<<" "<<R<<endl;
    		return query(root[l],root[r],1,n);
    	}
    };
    void dfs(int x){
    	pre[x]=++dfs_clock;
    	//printf("%d %d %d %d
    ",x,pre[x],val[x],fa[x][0]);
    	for(int i=linkk[x];i;i=e[i].next){
    		if(e[i].y==fa[x][0])continue;
    		dep[e[i].y]=dep[x]+1;
    		fa[e[i].y][0]=x;
    		dfs(e[i].y);
    	}
    	low[x]=dfs_clock;
    }
    bool check(int a,int b,int c,int d){//返回c,d位置是否有right集有a,b的元素
    	int y=zuo[d];
    	for(int i=25;i>=0;i--)
    		if(Sam::len[fa[y][i]]>=c)y=fa[y][i];//定位c,d字符串
    	int sum=chair_man_tree::Query(pre[y]-1,low[y],a,b);
    	if(sum)return 1;
    	else return 0;
    }
    int main(){
    	freopen(FILE".in","r",stdin);
    	freopen(FILE".out","w",stdout);
    	n=read(),m=read();
    	scanf("%s",s+1);
    	reverse(s+1,s+n+1);
    	Sam::build();
    	Sam::prepare();
    	dfs(1);
    	up(i,1,Sam::cnt)id[pre[i]]=i;//主席树对应树
    	up(i,1,Sam::cnt)r[i]=val[id[i]];
    	chair_man_tree::n=Sam::cnt;
    	chair_man_tree::build();
    	for(int j=1;j<=25;j++)
    		for(int i=1;i<=Sam::cnt;i++)
    			fa[i][j]=fa[fa[i][j-1]][j-1];
    	while(m--){
    		int a=n-read()+1,b=n-read()+1,c=n-read()+1,d=n-read()+1;
    		swap(a,b);swap(c,d);
    		int left=1,right=min(d-c+1,b-a+1),ans=0;
    		while(left<=right){
    			int mid=(left+right)>>1;
    			if(check(a+mid-1,b,mid,d))left=mid+1,ans=mid;
    			else right=mid-1;
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    初步掌握HDFS的架构及原理
    Hadoop 生态系统
    安装Hadoop,让word count飞起来
    十分钟看透MapReduce
    初识Hadoop
    线性回归-理论篇
    逻辑回归
    hdu 4848 Wow! Such Conquering! (floyd dfs)
    hdu 4856 Tunnels (记忆化搜索)
    poj 3237 Tree [LCA] (树链剖分)
  • 原文地址:https://www.cnblogs.com/chadinblog/p/6522961.html
Copyright © 2011-2022 走看看