本蒟蒻看了题解,然后自己写了一份SAM+倍增+线段树合并的版本,起初merge用传参版本,一直WA,函数代码如下:
void merge(int &x,int &y,int l,int r){
if(!x){
x=++tot;
tree[tot]=tree[y];
return ;
}
if(!y) return ;
int z=++tot;
if(l==r){
tree[z].Mc=tree[x].Mc+tree[y].Mc;
tree[z].M=l;
x=z;
return ;
}
int mid=l+r>>1,ls,rs;
merge(tree[x].ls,tree[y].ls,l,mid);
merge(tree[x].rs,tree[y].rs,mid+1,r);
ls=tree[x].ls,rs=tree[x].rs;
tree[z].ls=tree[x].ls,tree[z].rs=tree[x].rs;
if(!ls) tree[z].M=tree[rs].M,tree[z].Mc=tree[rs].Mc;
else if(!rs) tree[z].M=tree[ls].M,tree[z].Mc=tree[ls].Mc;
else {
tree[z].Mc=max(tree[ls].Mc,tree[rs].Mc);
if(tree[ls].Mc>=tree[rs].Mc) tree[z].M=tree[ls].M;
else tree[z].M=tree[rs].M;
}
x=z;
return ;
}
后来换成了int返回合并后的节点编号的版本,就过了,请问dl们这是为什么呢? int版本代码如下:
int merge(int x,int y,int l,int r){
if(!x || !y) return x|y;
int z=++tot;tree[z]=tree[x];
if(l==r){
tree[z].Mc+=tree[y].Mc;
tree[z].M=l;
return z;
}
int mid=l+r>>1,ls,rs;
tree[z].ls=merge(tree[x].ls,tree[y].ls,l,mid);
tree[z].rs=merge(tree[x].rs,tree[y].rs,mid+1,r);
ls=tree[z].ls,rs=tree[z].rs;
tree[z].Mc=max(tree[ls].Mc,tree[rs].Mc);
if(tree[ls].Mc>=tree[rs].Mc) tree[z].M=tree[ls].M;
else tree[z].M=tree[rs].M;
return z;
}
其中,M保存出现次数最多的字符串的编号,Mc保存出现次数。