Вы, возможно, не найдете здесь каждый шаг полезным, и вы можете проверить это на больших примерах:
library(data.table)
dt <- data.table(df_foo)
setkeyv(dt, c("From", "To"))
dt.all <- foverlaps(dt, dt, by.x = c("From", "To"))
dt.all[To > i.To & i.From > From, `:=`(From = i.To)]
dt.all <- unique(dt.all[order(From)], by = "From")
dt.all[, from.next := shift(From, type = "lead")]
dt.all[!is.na(from.next), To := ifelse(To > from.next, from.next, To)]
dt.all[, str.grp := shift(Str, fill = TRUE) != Str]
dt.all[, str.grp.n := cumsum(str.grp)]
dt.all[, from.in.group := shift(From), by = .(Str, str.grp.n)]
dt.all[, to.previous := shift(To)]
dt.all[, from.previous := shift(From)]
dt.all[!is.na(from.in.group) & From == to.previous, `:=`(From = from.previous)]
res <- unique(dt.all[order(From, -To)], by = "From")
Надеюсь, это даст вам хорошее представление о том, как это сделать с таблицами данных.