zoukankan      html  css  js  c++  java
  • [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|
  • 相关阅读:
    php类型转换
    PHP标记
    使用PHP从web访问mysql数据库
    javascript string对象的属性与方法
    linux vim 常用命令
    添加事件监听兼容IE6-8
    js-jQuery对象与dom对象相互转换
    js 数组
    js正则表达式
    选择排序
  • 原文地址:https://www.cnblogs.com/wang9897/p/10357031.html
Copyright © 2011-2022 走看看