网络赛的画风都略有奇怪
但是我们发挥的更差了
话说网络赛没有题解真是气人!
I 是道好题,但是莫名奇妙T了
给出一些子串,求将它们顺次排列后序列,使相邻串lcp的字典序。
做法: 后缀树+虚树+树形dp
考场上没有想到dp的思想把每个子树中的序列按字典序排序后合并起来。分隔符是这个点的val。启发式合并保证复杂度。
当时写的奇奇怪怪的贪心细节很多没有考虑全面,调了很久也没有调出来。
把代码粘出来留坑。有两个问题:1. 可能是vec开得太多。不知道为什么超级慢,把maxn一开大就会慢
2. 在后缀树上定位串需要倍增,不能直接暴力跳
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define rvc(i,S) for(int i=0;i<(int)S.size();++i)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 4020
struct node{
int next,to;
}e[maxn];
int head[maxn],cnt,tot;
int id[maxn],sz[maxn],fa[maxn],mn[21][maxn * 2],num[maxn * 2],a[maxn * 2],dfstime,dth[maxn],dfn[maxn],len[maxn],pnt[maxn];
int stack_[maxn],tops,rec,rt,tag[maxn];
int n,m,T;
char ch[maxn];
vector <int> vec[maxn],son[maxn],ans,dt[maxn],p;
inline void adde(int x,int y){
e[++cnt].to = y;
e[cnt].next = head[x];
head[x] = cnt;
}
struct SAM{
int next[maxn][26],val[maxn],pnt[maxn],last,tot;
void clear(){
rep(i,0,tot) memset(next,0,sizeof(next)) , val[i] = pnt[i] = 0;
tot = last = 0;
}
void Add(int x){
int p = last , np = ++tot;
val[np] = val[p] + 1 , id[val[np]] = tot + 1;
while ( !next[p][x] && p ) next[p][x] = np , p = pnt[p];
int q = next[p][x];
if ( !q ) next[p][x] = np , pnt[np] = p;
else if ( val[p] + 1 == val[q] ) pnt[np] = q;
else{
int nq = ++tot;
val[nq] = val[p] + 1;
pnt[nq] = pnt[q];
pnt[np] = pnt[q] = nq;
memcpy(next[nq],next[q],sizeof(next[q]));
while ( p && next[p][x] == q ) next[p][x] = nq , p = pnt[p];
if ( next[p][x] == q ) next[p][x] = nq;
}
last = np;
}
void pre(){
rep(i,1,tot + 1) head[i] = 0;
cnt = 0;
rep(i,1,tot) adde(pnt[i] + 1,i + 1) , len[i + 1] = val[i];
}
void print(){
rep(i,1,tot) cout<<i + 1<<" "<<pnt[i] + 1<<endl;
}
}sam;
void clear(){
sam.clear();
cnt = tot = 0;
}
void clear2(){
cnt = 0;
tops = 0;
p.clear();
}
inline bool cmp(int x,int y){ return dfn[x] < dfn[y]; }
void dfs(int x){
a[++tot] = x , dfn[x] = tot;
for (int &i = head[x] ; i ; i = e[i].next){
pnt[e[i].to] = x , dth[e[i].to] = dth[x] + 1;
dfs(e[i].to);
a[++tot] = x;
}
}
void Init_Tree(){
dfs(1);
rep(i,1,tot){
num[i] = num[i - 1];
if ( (1 << (num[i] + 1)) < i ) num[i]++;
}
rep(i,1,tot) mn[0][i] = a[i];
rep(i,1,20){
rep(j,1,tot){
if ( j + (1 << (i - 1)) > tot || dth[mn[i - 1][j]] < dth[mn[i - 1][j + (1 << (i - 1))]] )
mn[i][j] = mn[i - 1][j];
else
mn[i][j] = mn[i - 1][j + (1 << (i -1))];
}
}
}
void init(){
rep(i,1,n) sam.Add(ch[i] - 'a');
sam.pre();
Init_Tree();
// sam.print();
}
inline int lca(int x,int y){
int l = dfn[x] , r = dfn[y];
if ( l > r ) swap(l,r);
int len = r - l + 1,c = num[len],id1 = mn[c][l],id2 = mn[c][r - (1 << c) + 1];
if ( dth[id1] < dth[id2] ) return id1;
return id2;
}
void insert(int x){
if ( !tops ){ stack_[++tops] = x; return; }
int v = stack_[tops] , lca_ = lca(v,x) , w = stack_[tops - 1];
while ( tops > 1 && dth[w] > dth[lca_] ){
adde(w,v);
tops--;
v = w;
w = stack_[tops - 1];
}
if ( v != lca_ ){
adde(lca_,v) , tops--;
if ( stack_[tops] != lca_ ) stack_[++tops] = lca_;
}
stack_[++tops] = x;
}
inline bool cmp2(int x,int y){
if ( !vec[x].size() ) return 0;
if ( !vec[y].size() ) return 1;
rep(i,0,min(vec[x].size(),vec[y].size()) - 1) if ( vec[x][i] != vec[y][i] ) return vec[x][i] > vec[y][i];
return vec[x].size() > vec[y].size();
}
inline void merge(int x,int y){
if ( vec[x].size() > vec[y].size() ){
rvc(i,vec[y]) vec[x].pb(vec[y][i]);
}
else{
rvc(i,vec[x]) vec[y].pb(vec[x][i]);
//vec[x].begin() = vec[y].begin();
//vec[x].swap(vec[y]);
swap(vec[x],vec[y]);
}
}
void dfs2(int x){
for (int i = head[x] ; i ; i = e[i].next){
dfs2(e[i].to);
if ( sz[e[i].to] ) son[x].pb(e[i].to);
sz[x] += sz[e[i].to];
}
sort(son[x].begin(),son[x].end(),cmp2);
rvc(i,son[x]){
merge(x,son[x][i]);
if ( i < (int)son[x].size() - 1 ) vec[x].pb(len[x]);
}
if ( dt[x].size() && son[x].size() ) vec[x].pb(dt[x].back());
while ( dt[x].size() > 1 ) vec[x].pb(dt[x][dt[x].size() - 2]) , dt[x].pop_back();
}
void dfs_c(int x){
vec[x].clear() , dt[x].clear() , son[x].clear();
sz[x] = 0;
for (int &i = head[x] ; i ; i = e[i].next){
fa[e[i].to] = 0;
dfs_c(e[i].to);
}
}
void solve(){
dfs_c(rt);
clear2();
int t,l,r,clen,cur;
scanf("%d",&t);
rep(i,1,t){
scanf("%d %d",&l,&r) , l++ , r++;
clen = r - l + 1 , l = n - l + 1;
cur = id[l];
while ( clen <= len[pnt[cur]] ) cur = pnt[cur];
sz[cur]++ , p.pb(cur) , dt[cur].pb(clen);
}
sort(p.begin(),p.end(),cmp);
p.erase(unique(p.begin(),p.end()),p.end());
rvc(i,p) insert(p[i]);
// rvc(i,p) cout<<p[i]<<" ";
// cout<<endl;
while ( tops > 1 ) adde(stack_[tops - 1],stack_[tops]) , tops--;
rt = stack_[1];
dfs2(rt);
rvc(i,vec[rt]){
printf("%d",vec[rt][i]);
if ( i < vec[rt].size() - 1 ) printf(" ");
else printf("\n");
}
}
int main(){
freopen("input.txt","r",stdin);
scanf("%d",&T);
rep(t,1,T){
printf("Case %d:\n",t);
clear();
scanf("%d %d",&n,&m);
scanf("%s",ch + 1);
reverse(ch + 1,ch + n + 1);
init();
while ( m-- ){
solve();
}
}
}