題目鏈接:[COCI 2009] PASIJANS
顯然我們每次貪心用堆維護最小的。
但是如果有相同的怎麼選擇呢?我們就要往後比較了。所以就是一個後綴排序的問題了。
但是要注意,字符串4 2是大於字符串4 2 3的。
所以我們在每個字符串後面增加一個極大值。
AC代碼:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=2e6+10;
int n,s[N],num[N],cnt,m,sum[N];
vector<int> v;
struct node{int pos,val,id;};
bool operator < (node a,node b){return a.val>b.val;}
priority_queue<node> q;
int y[N],x[N],c[N],sa[N],rk[N],h[N];
char *fs,*ft,buf[1<<20];
#define gc() (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<20,stdin),fs==ft))?0:*fs++;
inline int read(){
int x=0,f=1; char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=gc();}
return x*f;
}
void get_SA(int n,int m){
for(int i=1;i<=n;i++) ++c[x[i]=s[i]];
for(int i=2;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i>=1;i--) sa[c[x[i]]--]=i;
for(int k=1,num;k<=n;k<<=1){
num=0;
for(int i=n-k+1;i<=n;i++) y[++num]=i;
for(int i=1;i<=n;i++) if(sa[i]>k) y[++num]=sa[i]-k;
for(int i=1;i<=m;i++) c[i]=0;
for(int i=1;i<=n;i++) ++c[x[i]];
for(int i=2;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i>=1;i--) sa[c[x[y[i]]]--]=y[i],y[i]=0;
swap(x,y),x[sa[1]]=1,num=1;
for(int i=2;i<=n;i++)
x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
if(num==n) break; m=num;
}
for(int i=1;i<=n;i++) rk[sa[i]]=i;
}
void write(int x){if(x>9) write(x/10);putchar(x%10+'0');}
signed main(){
n=read(); v.push_back(1e9);
for(int i=1;i<=n;i++){
num[i]=read(); sum[i]=sum[i-1]+num[i]+1;
for(int j=1;j<=num[i];j++) s[++cnt]=read(),v.push_back(s[cnt]);
s[++cnt]=1e9;
}
sort(v.begin(),v.end()); v.erase(unique(v.begin(),v.end()),v.end()); m=v.size();
for(int i=1;i<=cnt;i++) s[i]=lower_bound(v.begin(),v.end(),s[i])-v.begin()+1;
get_SA(cnt,m);
for(int i=1;i<=n;i++) q.push({1,rk[sum[i-1]+1],i});
while(q.size()){
node u=q.top(); q.pop();
write(v[s[sum[u.id-1]+u.pos]-1]),putchar(' ');
if(u.pos<num[u.id]) q.push({u.pos+1,rk[sum[u.id-1]+u.pos+1],u.id});
}
return 0;
}