题解 CF240F TorCoder
题意
给定一个由 $\texttt{a}$ 至 $\texttt{z}$ 组成的字符串,支持:
- 重构区间 $\left[l,r\right]$ 使其构成一个字典序最小的回文串。
- 最后整体查询。
题解
让重构的回文串字典序最小,就要让字典序小的排到更接近 $l,r$ 的位置,所以字典序小的字母优先计算。
对于每个字母,开棵线段树,维护该字母在区间内出现的次数,每次重构操作就推平,按字典序从小到大填满整个区间,这个很容易实现。
构造时区间长度会影响判断无解。
-
当区间长度为奇数时,至少有一类字母出现次数为奇数,把这类字母放一个到回文中心。如果出现次数为奇数的字母数大于 $1$,显然回文串构造不出来,无解。
-
当区间长度为偶数时,若存在某类字母出现了奇数,显然就构造不出,且每次会出现至少 $2$ 类,所以可以和第一类一起判了。
按字典序从 $\texttt{a}$ 到 $\texttt{z}$ 依次推平重构即可满足构成字典序最小的字符串。
时间复杂度为 $O(n\log n)$,再乘个字符集的常数 $O(\Sigma)$,$\Sigma=26$。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, Sigma = 26;
int n, m;
char s[N];
int a[N];
struct SegmentTree {
int tag, sum, l, r;
} t[Sigma][N << 2];
#define ls x << 1
#define rs x << 1 | 1
void pushup(int num, int x) { t[num][x].sum = t[num][ls].sum + t[num][rs].sum; }
void pushdown(int num, int x) {
if(~t[num][x].tag) {
t[num][ls].tag = t[num][rs].tag = t[num][x].tag;
t[num][ls].sum = (t[num][ls].r - t[num][ls].l + 1) * t[num][ls].tag;
t[num][rs].sum = (t[num][rs].r - t[num][rs].l + 1) * t[num][rs].tag;
t[num][x].tag = -1;
}
}
void build(int num, int x, int l, int r) {
t[num][x].l = l, t[num][x].r = r, t[num][x].tag = -1;
if(l == r) {
t[num][x].sum = a[l] == num;
return;
}
int mid = (l + r) >> 1;
build(num, ls, l, mid);
build(num, rs, mid + 1, r);
pushup(num, x);
}
void update(int num, int x, int l, int r, int val) {
if(l <= t[num][x].l && t[num][x].r <= r) {
t[num][x].tag = val;
t[num][x].sum = (t[num][x].r - t[num][x].l + 1) * val;
return;
}
pushdown(num, x);
if(l <= t[num][ls].r) update(num, ls, l, r, val);
if(t[num][rs].l <= r) update(num, rs, l, r, val);
pushup(num, x);
}
int query(int num, int x, int l, int r) {
if(l <= t[num][x].l && t[num][x].r <= r)
return t[num][x].sum;
pushdown(num, x);
int res = 0;
if(l <= t[num][ls].r) res += query(num, ls, l, r);
if(t[num][rs].l <= r) res += query(num, rs, l, r);
return res;
}
int cnt[Sigma], num, tot, curl, curr;
bool check;
int main() {
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
scanf("%d%d%s", &n, &m, s + 1);
for(int i = 1; i <= n; i++)
a[i] = s[i] - 'a';
for(int i = 0; i < Sigma; i++)
build(i, 1, 1, n);
while(m--) {
int l, r;
tot = num = 0;
scanf("%d%d", &l, &r);
curl = l, curr = r;
check = false;
for(int i = 0; i < Sigma; i++) {
cnt[i] = query(i, 1, l, r);
if(cnt[i] & 1)
tot++, num = i;
if(tot > 1) {
check = true;
break;
}
}
if(check) continue;
for(int i = 0; i < Sigma; i++)
update(i, 1, l, r, 0);
if((r - l + 1) & 1)
cnt[num]--;
for(int i = 0; i < Sigma; i++)
if(cnt[i]) {
update(i, 1, curl, curl + (cnt[i] >> 1) - 1, 1);
update(i, 1, curr - (cnt[i] >> 1) + 1, curr, 1);
curl += (cnt[i] >> 1), curr -= (cnt[i] >> 1);
}
if((r - l + 1) & 1)
update(num, 1, (l + r) >> 1, (l + r) >> 1, 1);
}
for(int i = 1; i <= n; i++)
for(int j = 0; j < Sigma; j++)
if(query(j, 1, i, i)) {
printf("%c", j + 'a');
break;
}
return 0;
}

浙公网安备 33010602011771号