• bzoj 4453 cys就是要拿英魂! —— 后缀数组+单调栈+set


    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4453

    这种问题...一般先把询问离线,排序;

    区间对后缀排名的影响在于一些排名大而位置靠后的后缀可能因为区间右端点截掉了后面而排名变小;

    考虑如何影响:如果 i < j

    rk[i] > rk[j] ,那么字典序 i 一直大于 j

    rk[i] < rk[j] ,那么如果右端点 R <= j + LCP(i,j),字典序 i > j,如果 R > j + LCP(i,j),字典序 i < j

    而如果对询问区间按右端点排序,右端点就是递增的;

    需要处理一下 i < j , rk[i] < rk[j] 的情况,由于每个 i 只考虑暂时大于它后面第一个 j (若还有 k,之后考虑 j 暂时大于 k),所以用单调栈找到后面第一个大于的;

    有类似插入、删除这样的操作,可以用 set 维护,当 R > j + LCP 后,就把 i 删除;

    令 set 里面是当前有贡献的位置,也就是单调栈里的位置和虽然被弹出但暂时大于后面某个后缀的位置;

    然后在位置上开个 vector 记录到这个地方贡献就失效的后缀,到了后把它们再从 set 里删除;

    因为 set 里位置的贡献也是从左到右单调递减的,那么每次取 L 右边第一个就是答案;

    别写错ST表!

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<set>
    #include<vector>
    #define pb push_back
    using namespace std;
    int const xn=1e5+5;
    int n,m,tax[xn],tp[xn],sa[xn],rk[xn],sta[xn],top,dc[xn],ht[xn][20],bin[20],r[xn],ans[xn];
    char s[xn];
    vector<int>v[xn],com[xn];
    set<int>st;
    set<int>::iterator it;
    struct N{int l,r,id;}q[xn];
    bool cmp(N x,N y){return x.r<y.r;}
    int rd()
    {
      int ret=0,f=1; char ch=getchar();
      while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
      while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
      return f?ret:-ret;
    }
    void Rsort()
    {
      for(int i=1;i<=m;i++)tax[i]=0;
      for(int i=1;i<=n;i++)tax[rk[tp[i]]]++;
      for(int i=1;i<=m;i++)tax[i]+=tax[i-1];
      for(int i=n;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];
    }
    void work()
    {
      for(int i=1;i<=n;i++)rk[i]=s[i],tp[i]=i;
      Rsort();
      for(int k=1;k<=n;k<<=1)
        {
          int num=0;
          for(int i=n-k+1;i<=n;i++)tp[++num]=i;
          for(int i=1;i<=n;i++)
        if(sa[i]>k)tp[++num]=sa[i]-k;
          Rsort(); swap(rk,tp);
          rk[sa[1]]=1; num=1;
          for(int i=2;i<=n;i++)
        rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k])?num:++num;
          if(num==n)break;
          m=num;
        }
    }
    void get()
    {
      int k=0;
      for(int i=1;i<=n;i++)
        {
          if(rk[i]==1)continue;
          if(k)k--; int j=sa[rk[i]-1];
          while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
          ht[rk[i]][0]=k;
        }
      bin[0]=1; for(int i=1;i<20;i++)bin[i]=(bin[i-1]<<1);
      r[1]=0; for(int i=2;i<=n;i++)r[i]=r[i>>1]+1;
      for(int j=1;j<20;j++)
        for(int i=1;i<=n&&i+bin[j]-1<=n;i++)
          ht[i][j]=min(ht[i][j-1],ht[i+bin[j-1]][j-1]);//
    }
    int getlcp(int x,int y)
    {
      if(x==y)return n;
      x=rk[x]; y=rk[y];
      if(x>y)swap(x,y); x++;
      int w=r[y-x+1];
      return min(ht[x][w],ht[y-bin[w]+1][w]);//
    }
    int main()
    {
      scanf("%s",s+1); n=strlen(s+1);
      for(int i=1;i<=n;i++)dc[i]=(int)s[i];
      sort(dc+1,dc+n+1); m=unique(dc+1,dc+n+1)-dc-1;
      for(int i=1;i<=n;i++)s[i]=lower_bound(dc+1,dc+m+1,(int)s[i])-dc;
      work(); get();
      int Q=rd();
      for(int i=1;i<=Q;i++)q[i].l=rd(),q[i].r=rd(),q[i].id=i;
      sort(q+1,q+Q+1,cmp); int p=0;
      for(int i=1;i<=Q;i++)
        {
          while(p<q[i].r)
        {
          p++; int y;
          while(rk[y=sta[top]]<rk[p]&&top)//<
            {
              int pos=min(n+1,p+getlcp(y,p));
              v[pos].pb(y); com[p].pb(y);
              top--;
            }
          sta[++top]=p; st.insert(p);
          for(int i=0,x;i<v[p].size();i++)
            if(st.count(x=v[p][i]))
              {
            for(int j=0;j<com[x].size();j++)
              if(st.count(com[x][j]))st.erase(com[x][j]);
            st.erase(x);
              }
        }
          it=st.lower_bound(q[i].l);
          ans[q[i].id]=*it;
        }
      for(int i=1;i<=Q;i++)printf("%d
    ",ans[i]);
      return 0;
    }
  • 相关阅读:
    Bank4
    Bank3
    Bank2
    Bank1
    Kubernetes核心技术Service
    kubernetes的Pod
    kubernetes如何快速编写yaml文件
    Kuberbetes的Secret
    Kuberbetes的Job和CronJob
    Kuberbetes的DaemonSet
  • 原文地址:https://www.cnblogs.com/Zinn/p/10083295.html
Copyright © 2020-2023  润新知