bzoj 4278 [ONTAK2015]Tasowanie——后缀数组

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

因为每次要放后缀较小的那个,所以把两个序列放在一起排序吧。改一改模板。

其实要改的地方就是让后面序列那部分不要在倍增的时候更新前面序列那部分。

考虑 4 和 43 ,应该是 43 比 4 小;因为放了单独的 4 的话就只能放 43 ,而放了 43 的 4 的话可以放 3 再放单独的 4 。

  即,前缀相等的话短的比较大、长的比较小。把 n-k+1 ~ n 的那个赋值放在 if( sa[i] > k ) 的赋值后面就行了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=4e5+5;
int n,m,tn,a[N],sa[N],tp[N],rk[N],tx[N];
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
void Rsort(int nm)
{
  for(int i=1;i<=nm;i++)tx[i]=0;
  for(int i=1;i<=tn;i++)tx[rk[i]]++;
  for(int i=2;i<=nm;i++)tx[i]+=tx[i-1];
  for(int i=tn;i;i--)sa[tx[rk[tp[i]]]--]=tp[i];
}
void work()
{
  int nm=1000;
  for(int i=1;i<=tn;i++)tp[i]=i,rk[i]=a[i];
  Rsort(nm);
  for(int k=1;k<=tn;k<<=1)
    {
      int tot=0;
      for(int i=1,j=n+k;i<=tn;i++)
    if((sa[i]<=n&&sa[i]>k)||(sa[i]>j))
      tp[++tot]=sa[i]-k;
      for(int i=max(1,n-k+1);i<=n;i++)tp[++tot]=i;//max//here after ...
      for(int i=max(n+1,tn-k+1);i<=tn;i++)tp[++tot]=i;
      Rsort(nm);
      swap(rk,tp);nm=1;rk[sa[1]]=1;
      for(int i=2,u,v;i<=tn;i++)
    {
      u=sa[i]+k;v=sa[i-1]+k;
      if((sa[i]<=n&&u>n)||(sa[i]>n&&u>tn))u=0;
      if((sa[i-1]<=n&&v>n)||(sa[i-1]>n&&v>tn))v=0;
      rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[u]==tp[v])?nm:++nm;//rk[sa[i]]
    }
      if(nm==tn)break;
    }
}
int main()
{
  n=rdn();for(int i=1;i<=n;i++)a[i]=rdn();
  m=rdn();tn=n+m;for(int i=n+1;i<=tn;i++)a[i]=rdn();
  work();
  int p0=1,p1=n+1;
  for(int i=1;i<=tn;i++)
    {
      if(rk[p0]<rk[p1])printf("%d ",a[p0]),p0++;
      else printf("%d ",a[p1]),p1++;
      if(p0>n||p1>tn)break;
    }
  if(p0<=n)for(;p0<=n;p0++)printf("%d ",a[p0]);
  if(p1<=tn)for(;p1<=tn;p1++)printf("%d ",a[p1]);
  puts("");
  return 0;
}
原文地址:https://www.cnblogs.com/Narh/p/10075775.html