[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
",ans[i]+1);
}

  

4453: cys就是要拿英魂!

Time Limit: 3 Sec  Memory Limit: 128 MB
Submit: 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

Sample Output

2
3
3
3
3
数据范围:
1<=|S|<=100000
1<=Q<=100000
1<=l<=r<=|S|
原文地址:https://www.cnblogs.com/wang9897/p/10357031.html