zoukankan      html  css  js  c++  java
  • [JZOJ6241]【NOI2019模拟2019.6.29】字符串【数据结构】【字符串】

    Description

    给出一个长为n的字符串(S)和一个长为n的序列(a)
    定义一个函数(f(l,r))表示子串(S[l..r])的任意两个后缀的最长公共前缀的最大值。

    现在有q组询问,每组询问给出(L,R,x)
    你需要找到一个子串(S[l,r])满足([l,r]subset[L,R])(f(l,r)geq x)
    同时需要满足(max(a[l..r]))最小

    求这个最小值,无解则输出-1
    (n,qleq 50000)

    Solution

    这道题实际上分成两部分(谴责拼题行为)

    第一部分快速计算f(l,r)
    建出SAM,用个set维护right集,在parent树上启发式合并,显然Right集合中我们只需要考虑哪些相邻的位置有用(不相邻显然不优),合并的时候把要插入的位置的前驱以及它们的LCP构成一个三元组,后继也一样处理,这样我们得到了一个可能更新答案的三元组序列((l,x,r)),表示(S[l..x]=S[r-(x-l),r])

    观察对答案的贡献,它能贡献的区间满足(R>r,l<=x),相当于区间取max以及区间对等差数列取max
    维护两棵线段树分别来弄,等差数列我们只需要维护合法右端点最大值即可,两个都是区间取max单点查询,可以用struct写在一起

    还需要保证右端点的限制,因此对所有二元组按右端点排序建主席树即可。
    区间修改的主席树似乎比较麻烦?我们发现这题不需要下传标记,因此直接先将当前位置的操作扔进去再继承前一个的。

    这样就能够在(O(nlog^2n))预处理(启发式合并),(O(log n))计算一个区间的f

    第二部分计算答案

    显然只有笛卡尔树上的n个极大区间是有用的,计算出它们的f

    对于查询区间([L,R]),我们只需要找到被它完全包含的极大区间,然后分别以左右端点开始二分另一个端点即可。

    找到包含的区间似乎是个二维问题?

    不需要
    对于左端点我们二分了一个位置,表示右端点在这左边的都不合法。

    其他的合法区间的右端点一定在这右边,

    此时我们不需要管左端点的限制了,因为超出去答案显然更劣。
    直接一维区间最大值即可

    这一部分也是(O(nlog^2n))

    常数似乎比较大。

    Code

    代码足足有5K
    略毒瘤。

    #include <bits/stdc++.h>
    #define fo(i,a,b) for(int i=a;i<=b;++i)
    #define fod(i,a,b) for(int i=a;i>=b;--i)
    const int N=50005;
    using namespace std;
    char ch[N];
    int n,q;
    struct node
    {
    	int l,x,r;
    	friend bool operator <(node x,node y)
    	{
    		return x.r<y.r;
    	}
    };
    vector<node> ap;
    
    namespace SAM
    {
    	const int R=N<<1;
    	int t[R][26],mx[R],m1,ft[R],fs[R],nt[R],dt[R],n2,rf[R];
    	set<int> ri[R];
    	void link(int x,int y)
    	{
    		nt[++m1]=fs[x];
    		dt[fs[x]=m1]=y;
    	}
    	void merge(int x,int y,int v)
    	{
    		if(v==0) return;
    		if(ri[rf[x]].size()<ri[rf[y]].size()) swap(rf[x],rf[y]);
    		for(int i:ri[rf[y]])
    		{
    			set<int>::iterator it=ri[rf[x]].lower_bound(i);
    			if(it!=ri[rf[x]].end()) ap.push_back((node){i-v+1,i,*it});
    			if(it!=ri[rf[x]].begin()) it--,ap.push_back((node){*it-v+1,*it,i});
    			ri[rf[x]].insert(i);
    		}
    	}	
    	void dfs(int k)
    	{
    		int w=0;
    		for(int i=fs[k];i;i=nt[i])
    		{
    			int p=dt[i];
    			dfs(p);
    			merge(k,p,mx[k]);
    		}		
    	}
    	void make()
    	{	
    		n2=1;
    		int ls=n2;
    		fo(i,1,n)
    		{
    			int c=ch[i]-'a',p=ls;
    			mx[ls=++n2]=i;
    			rf[ls]=ls;
    			ri[ls].insert(i);
    			while(p&&!t[p][c]) t[p][c]=ls,p=ft[p];
    			if(t[p][c])
    			{
    				int q=t[p][c];
    				if(mx[q]==mx[p]+1) ft[ls]=q;
    				else
    				{
    					mx[++n2]=mx[p]+1;
    					ft[n2]=ft[q];
    					ft[q]=ft[ls]=n2;
    					memcpy(t[n2],t[q],sizeof(t[n2]));
    					while(p&&t[p][c]==q) t[p][c]=n2,p=ft[p];
    				}
    			}
    			else ft[ls]=1;
    		}
    		fo(i,2,n2) link(ft[i],i);
    		dfs(1);
    	}
    }
    
    namespace QS
    {
    	const int M=10000000;
    	
    	struct SGT
    	{
    		int t[M][2],mx[M],rt[N],n1;
    		inline int nwp(int &x)
    		{ 
    			if(!x) x=++n1,t[x][0]=t[x][1]=mx[x]=0;
    			return x;
    		}
    		void modify(int k,int l,int r,int x,int y,int v)
    		{
    			if(x>y) return;
    			if(x<=l&&r<=y) {mx[k]=max(mx[k],v);return;}	
    			int mid=(l+r)>>1;
    			if(x<=mid) modify(nwp(t[k][0]),l,mid,x,y,v);
    			if(y>mid) modify(nwp(t[k][1]),mid+1,r,x,y,v);
    		}
    		void merge(int &k,int w,int l,int r)
    		{
    			if(!k) {k=w;return;}
    			if(!w) return;
    			mx[k]=max(mx[k],mx[w]);
    			int mid=(l+r)>>1;
    			merge(t[k][0],t[w][0],l,mid);
    			merge(t[k][1],t[w][1],mid+1,r);
    		}
    		int query(int k,int l,int r,int x)
    		{
    			if(l==r) return mx[k];
    			int mid=(l+r)>>1,s=0;
    			if(x<=mid) s=query(t[k][0],l,mid,x);
    			else s=query(t[k][1],mid+1,r,x);
    			return max(s,mx[k]);
    		}
    	}T1,T2;
    	void make()
    	{
    		SAM::make();
    		sort(ap.begin(),ap.end());
    		
    		int r=ap.size()-1;
    		for(int i=1,j=0;i<=n;++i)
    		{
    			T1.rt[i]=++T1.n1;
    			T2.rt[i]=++T2.n1;
    			while(j<=r&&ap[j].r<=i)
    			{
    				T1.modify(T1.rt[i],1,n,1,ap[j].l-1,ap[j].x-ap[j].l+1);
    				T2.modify(T2.rt[i],1,n,ap[j].l,ap[j].x,ap[j].x);
    				j++;
    			}
    			T1.merge(T1.rt[i],T1.rt[i-1],1,n);
    			T2.merge(T2.rt[i],T2.rt[i-1],1,n);
    		}
    		n++;
    		n--;
    	}
    	int get(int l,int r)
    	{
    		return max(T1.query(T1.rt[r],1,n,l),min(T2.query(T2.rt[r],1,n,l),r)-l+1);
    	}
    }
    using QS::get;
    
    int a[N];
    struct px
    {
    	int l,r,v,c;
    	friend bool operator <(px x,px y) {return x.v>y.v;}
    }aw[N];
    
    int ask[N][3],d[N];
    bool cmp(int x,int y) {return ask[x][2]>ask[y][2];}
    int lf[N],rf[N],st[N],ans[N];
    
    namespace Tr
    {
    	int n1,t[N<<1][2],mx[N<<1],mi[N<<1];
    	void build(int k,int l,int r)
    	{
    		mi[k]=1e9;
    		if(l==r) {mx[k]=a[l];return;}
    		int mid=(l+r)>>1;
    		build(t[k][0]=++n1,l,mid),build(t[k][1]=++n1,mid+1,r);
    		mx[k]=max(mx[t[k][0]],mx[t[k][1]]);
    	}
    	void ins(int k,int l,int r,int x,int v)
    	{
    		if(l==r) {mi[k]=min(mi[k],v);return;}
    		int mid=(l+r)>>1;
    		if(x<=mid) ins(t[k][0],l,mid,x,v);
    		else ins(t[k][1],mid+1,r,x,v);
    		mi[k]=min(mi[t[k][0]],mi[t[k][1]]);
    	}
    	int ds[N];
    	void query(int k,int l,int r,int x,int y)
    	{
    		if(x>y) return;
    		if(x<=l&&r<=y) {ds[++ds[0]]=k;return;}
    		int mid=(l+r)>>1;
    		if(x<=mid) query(t[k][0],l,mid,x,y);
    		if(y>mid) query(t[k][1],mid+1,r,x,y);
    	}
    	int gmax(int l,int r)
    	{
    		ds[0]=0;
    		query(1,1,n,l,r);
    		int s=0;
    		fo(i,1,ds[0]) s=max(s,mx[ds[i]]);
    		return s;
    	}
    	int gmin(int l,int r)
    	{
    		ds[0]=0;
    		query(1,1,n,l,r);
    		int s=1e9;
    		fo(i,1,ds[0]) s=min(s,mi[ds[i]]);
    		return s;
    	}
    }
    using Tr::gmax;
    using Tr::gmin;
    int main()
    {
    	cin>>n>>q;
    	scanf("
    %s",ch+1);
    	QS::make();
    	fo(i,1,n) scanf("%d",&a[i]);
    	
    	fo(i,1,n)
    	{
    		while(st[0]&&a[i]>a[st[st[0]]]) rf[st[st[0]]]=i-1,st[st[0]--]=0;
    		st[++st[0]]=i;
    	}
    	while(st[0]) rf[st[st[0]]]=n,st[st[0]--]=0;
    	
    	fod(i,n,1)
    	{
    		while(st[0]&&a[i]>a[st[st[0]]]) lf[st[st[0]]]=i+1,st[st[0]--]=0;
    		st[++st[0]]=i;
    	}	
    	while(st[0]) lf[st[st[0]]]=1,st[st[0]--]=0;
    	
    	fo(i,1,n) aw[i]=(px){lf[i],rf[i],get(lf[i],rf[i]),a[i]};
    	sort(aw+1,aw+n+1);
    	
    	fo(i,1,q)
    	{
    		scanf("%d%d%d",&ask[i][0],&ask[i][1],&ask[i][2]);
    		d[i]=i;
    	}
    	sort(d+1,d+q+1,cmp);
    	int j=1;
    	Tr::n1=1;
    	Tr::build(1,1,n);
    	
    	fo(i,1,q)
    	{
    		while(j<=n&&aw[j].v>=ask[d[i]][2])
    		{
    			Tr::ins(1,1,n,aw[j].r,aw[j].c);
    			j++;
    		}
    		int l=ask[d[i]][0],r=ask[d[i]][1]+1;
    		while(l+1<r)
    		{
    			int mid=(l+r)>>1;
    			if(get(ask[d[i]][0],mid)>=ask[d[i]][2]) r=mid;
    			else l=mid;
    		}
    		int wp;
    		if(get(ask[d[i]][0],l)>=ask[d[i]][2]) wp=l;
    		else wp=r;
    		if(wp==ask[d[i]][1]+1) {ans[d[i]]=-1;continue;}
    		ans[d[i]]=min(gmax(ask[d[i]][0],wp),gmin(wp,ask[d[i]][1]));
    		
    		l=ask[d[i]][0],r=ask[d[i]][1];
    		while(l+1<r)
    		{
    			int mid=(l+r)>>1;
    			if(get(mid,ask[d[i]][1])>=ask[d[i]][2]) l=mid;
    			else r=mid;
    		}
    		if(get(r,ask[d[i]][1])>=ask[d[i]][2]) wp=r;
    		else wp=l;
    		ans[d[i]]=min(ans[d[i]],gmax(wp,ask[d[i]][1]));
    	}
    	fo(i,1,q) printf("%d
    ",ans[i]);
    }
    
  • 相关阅读:
    Ajax基础:3.Json
    Head First Design Patterns State Pattern
    Head First Design Patterns Template Method Pattern
    Articles For CSS Related
    Head First Design Patterns Decorator Pattern
    代码审查工具
    How To Be More Active In A Group
    Head First Design Patterns Factory Method Pattern
    Head First Design Patterns Composite Pattern
    Tech Articles
  • 原文地址:https://www.cnblogs.com/BAJimH/p/11111552.html
Copyright © 2011-2022 走看看