zoukankan      html  css  js  c++  java
  • 【BZOJ4453】cys就是要拿英魂! 后缀数组+单调栈+set

    【BZOJ4453】cys就是要拿英魂!

    Description

    pps又开始dota视频直播了!一群每天被pps虐的蒟蒻决定学习pps的操作技术,他们把pps在这局放的技能记录了下来,每个技能用一个字符表示。经过研究,蒟蒻们发现字典序更大的连招威力更大。于是所有蒟蒻都想学习pps最强的连招。但是他们太弱了,不能学会整个视频里的连招,只能学会陈老师一段区间间内的连招,可是这个他们求不出,于是只好向你求助。为了蒟蒻们不再被pps虐(怎么可能),请你帮帮他们。简化题意:给你一个字符串,每次询问你一段区间的字典序最大的子串。

    Input

    第一行是一个字符串S,表示pps放的技能
    第二行一个正整数Q,表示询问个数
    接下来Q行,每行两个正整数[l,r],表示询问区间[l,r]中的字典序最大的子串。

    Output

    Q行,每行一个正整数,表示该区间内字典序最大的子串的起始位置。

    Sample Input

    Lets_go_mod_p!
    5
    2 2
    3 3
    2 5
    1 10
    2 9

    Sample Output

    2
    3
    3
    3
    3
    数据范围:
    1<=|S|<=100000
    1<=Q<=100000
    1<=l<=r<=|S|

    题解:看到题,想都不用想一定是后缀数组+离线乱搞。然后就越搞越复杂。这里还是直接贴正解好了。

    注释:

    这里实际上是用单调栈优化set,不要搞反。

    标算的核心就是那个删除时刻的标记,还有那个“伴随”概念。更具体的做法是,我们对于每个点维护两套边,一套指向的是:有哪些点的删除标记是当前点,另一套指向的是:有哪些点伴随当前点。(形成了一个类似森林的结构?)这样,我们枚举那些删除树上的点,再DFS下去,删除所有伴随树上的点就行了。

    后缀数组的LCP不要写错啊啊啊~调了好久。

     

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <set>
    using namespace std;
    const int maxn=100010;
    int n,m,top,cnt;
    int ra[maxn],rb[maxn],st[maxn],r[maxn],sa[maxn],rank[maxn],h[maxn],f[maxn][20],sta[maxn];
    int Log[maxn],ans[maxn],to[maxn<<1],next[maxn<<1],hb[maxn],hd[maxn],del[maxn];
    char str[maxn];
    set<int> s;
    struct QUERY
    {
    	int ql,qr,org;
    }q[maxn];
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    bool cmp(QUERY a,QUERY b)
    {
    	return a.qr<b.qr;
    }
    void build()
    {
    	n++;
    	int i,j,k,p,*x=ra,*y=rb;
    	for(i=0;i<n;i++)	st[x[i]=r[i]]++;
    	for(i=1;i<m;i++)	st[i]+=st[i-1];
    	for(i=n-1;i>=0;i--)	sa[--st[x[i]]]=i;
    	for(j=p=1;p<n;m=p,j<<=1)
    	{
    		for(p=0,i=n-j;i<n;i++)	y[p++]=i;
    		for(i=0;i<n;i++)	if(sa[i]>=j)	y[p++]=sa[i]-j;
    		for(i=0;i<m;i++)	st[i]=0;
    		for(i=0;i<n;i++)	st[x[y[i]]]++;
    		for(i=1;i<m;i++)	st[i]+=st[i-1];
    		for(i=n-1;i>=0;i--)	sa[--st[x[y[i]]]]=y[i];
    		for(swap(x,y),x[sa[0]]=0,i=p=1;i<n;i++)
    			x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+j]==y[sa[i-1]+j])?p-1:p++;
    	}
    	for(i=1;i<n;i++)	rank[sa[i]]=i;
    	for(i=k=0;i<n-1;h[rank[i++]]=k)
    		for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
    	n--;
    	for(i=1;i<=n;i++)	f[i][0]=h[i];
    	for(i=2;i<=n;i++)	Log[i]=Log[i>>1]+1;
    	for(j=1;(1<<j)<=n;j++)	for(i=1;i+(1<<j)-1<=n;i++)	f[i][j]=min(f[i][j-1],f[i+(1<<j-1)][j-1]);
    }
    int getlcp(int a,int b)
    {
    	a=rank[a],b=rank[b];
    	if(a>b)	swap(a,b);
    	a++;
    	int k=Log[b-a+1];
    	return min(f[a][k],f[b-(1<<k)+1][k]);
    }
    void add(int c,int a,int b)
    {
    	if(a>=n)	return ;
    	to[cnt]=b;
    	if(c)	next[cnt]=hb[a],hb[a]=cnt++;
    	else	next[cnt]=hd[a],hd[a]=cnt++;
    }
    void dfs(int x)
    {
    	del[x]=1,s.erase(x);
    	for(int i=hb[x];i!=-1;i=next[i])	if(!del[to[i]])	dfs(to[i]);
    }
    void ins(int x)
    {
    	int i;
    	while(top)
    	{
    		if(rank[sta[top]]<rank[x])	add(0,x+getlcp(sta[top],x),sta[top]),add(1,x,sta[top]),top--;
    		else	break;
    	}
    	sta[++top]=x,s.insert(x);
    	for(i=hd[x];i!=-1;i=next[i])	if(!del[to[i]])	dfs(to[i]);
    }
    int main()
    {
    	memset(hb,-1,sizeof(hb));
    	memset(hd,-1,sizeof(hd));
    	scanf("%s",str),n=strlen(str);
    	int i,j;
    	for(i=0;i<n;i++)	r[i]=str[i],m=max(m,r[i]+1);
    	build();
    	m=rd();
    	for(i=1;i<=m;i++)	q[i].ql=rd()-1,q[i].qr=rd()-1,q[i].org=i;
    	sort(q+1,q+m+1,cmp);
    	for(i=1,j=0;i<=m;i++)
    	{
    		for(;q[i].qr>=j;j++)	ins(j);
    		ans[q[i].org]=*(s.lower_bound(q[i].ql));
    	}
    	for(i=1;i<=m;i++)	printf("%d
    ",ans[i]+1);
    	return 0;
    }

     

  • 相关阅读:
    PS常用美化处理方法大全
    FastReport.Net使用:[32]对话框使用2
    FastReport.Net使用:[31]使用带参查询及存储
    FastReport.Net使用:[30]对话框使用
    FastReport.Net使用:[29]调用存储过程1
    FastReport.Net使用:[28]数据合并
    FastReport.Net使用:[27]样式使用
    FastReport.Net使用:[26]数字格式
    FastReport.Net使用:[25]除数0处理方法
    FastReport.Net使用:[24]其他控件(邮政编码(Zip Code),网格文本(Cellular Text)以及线性刻度尺(Linear Gauge))
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7095317.html
Copyright © 2011-2022 走看看