[BZOJ]4453: cys就是要拿英魂!
题解:神题.....一眼看过去完全不知道怎么维护字典序最大
突破口在....离线所有询问从左往右加入后缀 然后对于三种情况分别讨论
当$ i<j $
若$ rank2[i]>rank2[j] $ 那么i最优性继续保持
若$ rank2[i]<rank2[j] $ 这里分情况讨论的是
$ i+lcp(i,j)-1>=j $ 这里i的最优性继续保持 只有当j超过了 $ i+lcp(i,j)-1 $时 i将丧失优势
因此我们用单调栈来维护 在j之前rank2小于j的位置 然后将删除标记打到他被删除的时刻 即当访问到删除时刻时 它及其子树都将被删除 还要注意的是 i位置依赖于j位置 若j位置在接下来的某个时刻丧失了优势 那么i同样会被删除掉 查询的话就是当前查询左端点的后继节点(具体看代码
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <stack> #include <queue> #include <cmath> #include <set> #include <map> #define mp make_pair #define pb push_back #define pii pair<int,int> #define link(x) for(edge *j=HH[x];j;j=j->next) #define inc(i,l,r) for(int i=l;i<=r;i++) #define dec(i,r,l) for(int i=r;i>=l;i--) const int MAXN=3e5+10; const double eps=1e-8; #define ll long long using namespace std; struct edge{int t,v;edge*next;}e[MAXN<<1],*HH[MAXN],*o=e; void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=HH[x];HH[x]=o++;} ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return x*f; } bool cmp(int t[],int f,int w,int k){return t[f]==t[w]&&t[f+k]==t[w+k];} int sa[MAXN],rank1[MAXN],rank2[MAXN],t1[MAXN],t2[MAXN],txt[MAXN],td[MAXN]; void Sa(char str[]){ int len=strlen(str);int m=250; int *td=t1;int *rank1=t2; for(int i=0;i<m;i++)txt[i]=0; for(int i=0;i<len;i++)txt[str[i]]++,rank1[i]=str[i]; for(int i=1;i<m;i++)txt[i]+=txt[i-1]; for(int i=len-1;i>=0;i--)sa[--txt[str[i]]]=i; for(int k=1;k<=len;k=k*2){ int p=0; for(int i=len-k;i<len;i++)td[p++]=i; for(int i=0;i<len;i++)if(sa[i]>=k)td[p++]=sa[i]-k; for(int i=0;i<m;i++)txt[i]=0; for(int i=0;i<len;i++)txt[rank1[i]]++; for(int i=1;i<m;i++)txt[i]+=txt[i-1]; for(int i=len-1;i>=0;i--)sa[--txt[rank1[td[i]]]]=td[i]; swap(rank1,td);rank1[sa[0]]=0; p=1; for(int i=1;i<len;i++)rank1[sa[i]]=cmp(td,sa[i],sa[i-1],k)?p-1:p++; if(p==len)return ; m=p; } } int H[MAXN],h[MAXN]; void hh(char str[]){ int len=strlen(str); memset(h,0,sizeof(h));memset(H,0,sizeof(H)); for(int i=0;i<len;i++)rank2[sa[i]]=i; for(int i=0;i<len;i++){ if(rank2[i]==0)continue; int t=sa[rank2[i]-1];int w=i;int k; if(i==0||H[i-1]<=1)k=0; else k=H[i-1]-1,t+=k,w+=k; while(t<len&&w<len){ if(str[t]==str[w])k++; else break; t++;w++; } H[i]=k;h[rank2[i]]=k; } } int dp[MAXN][21];int ma[MAXN]; void St(char str[]){ ma[0]=-1; for(int i=1;i<MAXN;i++)if((i&(i-1))==0)ma[i]=ma[i-1]+1;else ma[i]=ma[i-1]; int len=strlen(str); for(int i=1;i<len;i++)dp[i][0]=h[i]; for(int j=1;(1<<(j-1))<=len;j++){ for(int i=1;i+(1<<j)<=len;i++){ dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } } } int rmq(int l,int r){ if(l>r)swap(l,r); l++; int k=ma[r-l+1];int k1=(1<<k); return min(dp[l][k],dp[r-k1+1][k]); } char str[MAXN]; typedef struct node{ int l,r,id; friend bool operator<(node aa,node bb){return aa.r<bb.r;} }node; node que[MAXN]; set<int>s; int ans[MAXN]; vector<int>vec[MAXN]; bool vis[MAXN]; int st[MAXN],tot; void del(int x){ vis[x]=1;s.erase(s.lower_bound(x)); link(x){ if(!vis[j->t])del(j->t); } } void solve(int t,int len){ while(tot&&rank2[st[tot]]<rank2[t]){ int x=rmq(rank2[st[tot]],rank2[t]); if(t+x<len)vec[t+x].pb(st[tot]); add(x,st[tot],0); tot--; } st[++tot]=t;s.insert(t); for(int i=0;i<vec[t].size();i++)if(!vis[vec[t][i]])del(vec[t][i]); } int main(){ scanf("%s",str); int len=strlen(str);str[len]='!'; Sa(str);hh(str);St(str); int n=read(); inc(i,1,n)que[i].l=read(),que[i].r=read(),que[i].id=i; sort(que+1,que+n+1); int r=0; inc(i,1,n){ while(r<len&&r+1<=que[i].r)solve(r,len),r++; ans[que[i].id]=(*(s.lower_bound(que[i].l-1))); } inc(i,1,n)printf("%d\n",ans[i]+1); }
4453: cys就是要拿英魂!
Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 213 Solved: 104
[Submit][Status][Discuss]
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
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|
3
3
3
3
数据范围:
1<=|S|<=100000
1<=Q<=100000
1<=l<=r<=|S|