给定串 s s s, n n n 次操作,每次依次写下 [ l , r ] [l,r] [l,r] 的奇数下标字符,再写 [ l , r ] [l,r] [l,r] 的偶数下标字符,最后将写下的串插入到 r r r 位字符后。问最后串的前 k k k 位。
考虑倒着做,操作离线。发现对于一次操作就是删除一个对应的串。考虑删除后的串的字符在原串中的位置。直接拿一个线段树维护,初始全是 1 1 1,删除段区间赋值为 0 0 0,这样就可以查找第 k k k 大,删除后的第 k k k 个字符就是前缀和第 k k k 大。
将最终相同的位置用并查集串起来。
最后找到 s s s 的每个字符在最终的串中的位置。然后并查集查找会连到这些点上。
最终每个点都能找到对应的字符,因为并查集合并是由删掉的连向没删的,所以最后的根一定是没有被删掉的,即原串。
时间复杂度 O ( n α ( k ) log k ) O(n\space\alpha(k)\log k) O(n α(k)logk)。
#include
using namespace std;
const int N = 3000005;
int n, K, l[5005], r[5005], tr[N << 3], lz[N << 3], fa[N];
char s[N];
int col[N];
#define ls rt << 1
#define rs rt << 1 | 1
void pushdown(int rt) { if (lz[rt]) tr[ls] = tr[rs] = 0, lz[ls] = lz[rs] = 1, lz[rt] = 0; }
void bdtr(int rt, int x, int y) {
if (x == y) { tr[rt] = 1; return; }
int mid = x + y >> 1;
bdtr(ls, x, mid), bdtr(rs, mid + 1, y);
tr[rt] = tr[ls] + tr[rs];
}
void update(int rt, int x, int y, int l, int r) {
if (x > r || y < l) return;
pushdown(rt);
if (l <= x && y <= r) { tr[rt] = 0, lz[rt] = 1; return; }
int mid = x + y >> 1;
update(ls, x, mid, l, r), update(rs, mid + 1, y, l, r);
tr[rt] = tr[ls] + tr[rs];
}
int query(int rt, int x, int y, int k) {
if (x == y) return x;
int mid = x + y >> 1;
if (k <= tr[ls]) return query(ls, x, mid, k);
else return query(rs, mid + 1, y, k - tr[ls]);
}
#undef ls
#undef rs
int findfa(int x) { return !fa[x] ? x : fa[x] = findfa(fa[x]); }
int main() {
freopen("string.in", "r", stdin);
freopen("string.out", "w", stdout);
scanf("%s%d%d", s + 1, &K, &n), bdtr(1, 1, K);
for (int i = 1; i <= n; i++) scanf("%d%d", &l[i], &r[i]);
int tk = K;
for (int i = n; i >= 1; i--) {
if (r[i] >= tk) continue;
int x = r[i] + 1, y = min(tk, r[i] + r[i] - l[i] + 1);
int j = x;
for (int p = l[i] + 1 - (l[i] & 1); j <= y && p <= r[i]; j++, p += 2) {
int f1 = findfa(query(1, 1, K, j)), f2 = findfa(query(1, 1, K, p));
if (f1 != f2) fa[f1] = f2;
}
for (int p = l[i] + (l[i] & 1); j <= y && p <= r[i]; j++, p += 2) {
int f1 = findfa(query(1, 1, K, j)), f2 = findfa(query(1, 1, K, p));
if (f1 != f2) fa[f1] = f2;
}
update(1, 1, K, query(1, 1, K, x), query(1, 1, K, y)), tk -= y - x + 1;
}
int M = strlen(s + 1);
for (int i = 1; i <= M; i++) col[query(1, 1, K, i)] = i;
for (int i = 1; i <= K; i++) printf("%c", s[col[findfa(i)]]);
return 0;
}