线段树乱搞

考虑如果要重排一段区间使得它是回文的是可行的

首先对这段区间的长度分类讨论

如果它的长度是奇数,那么在这个区间的数肯定满足以下条件:

  • 有一个字母出现了奇数次(这个放在最中间)
  • 其他的出现了偶数次(放在旁边)

如果它的长度是偶数,那么这个区间内出现过的数肯定都出现过了偶数次

再考虑如何构造

  • 如果长度是奇数,把那个出现了奇数次的数放一个在最中间
  • 枚举A~Z,从最左和最右分别开始一直放(因为需要保证字典序最小)

容易发现这只需要线段树维护区间每个字母的出现次数就行了(也可以理解成26棵线段树)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include<bits/stdc++.h>

#define ll long long
#define INF 2147483647
#define lc(a) ((a) << 1)
#define rc(a) ((a) << 1 | 1)

int inp(){
char c = getchar();
while(c < '0' || c > '9')
c = getchar();
int sum = 0;
while(c >= '0' && c <= '9'){
sum = sum * 10 + c - '0';
c = getchar();
}
return sum;
}

struct SEG{
int l;
int r;
int sum[30];
int lazy;

void clear(){
memset(sum, 0, sizeof(sum));
}
};
int cnt[30];

char s[100010];

SEG operator + (SEG a, SEG b){
if(a.l == -1)
return b;
if(b.l == -1)
return a;
SEG ret;
ret.l = a.l;
ret.r = b.r;
for(int i = 0; i < 26; i++)
ret.sum[i] = a.sum[i] + b.sum[i];
return ret;
}

struct SEG_Tree{
SEG t[800010];

void push_up(int cur){
for(int i = 0; i < 26; i++)
t[cur].sum[i] = t[lc(cur)].sum[i] + t[rc(cur)].sum[i];
}

void build(int cur, int l, int r){
t[cur].lazy = -1;
t[cur].l = l;
t[cur].r = r;
if(l == r){
t[cur].clear();
t[cur].sum[s[l] - 'a'] = 1;
return ;
}
int mid = (l + r) >> 1;
build(lc(cur), l, mid);
build(rc(cur), mid + 1, r);
push_up(cur);
}

void push_down(int cur){
if(t[cur].lazy != -1){
t[lc(cur)].clear();
t[rc(cur)].clear();
t[lc(cur)].sum[t[cur].lazy] = t[lc(cur)].r - t[lc(cur)].l + 1;
t[rc(cur)].sum[t[cur].lazy] = t[rc(cur)].r - t[rc(cur)].l + 1;
t[lc(cur)].lazy = t[rc(cur)].lazy = t[cur].lazy;
}
t[cur].lazy = -1;
}

void query(int cur, int l, int r){
SEG nul;
nul.l = -1;
if(t[cur].l > r || t[cur].r < l)
return ;
push_down(cur);
if(t[cur].l >= l && t[cur].r <= r){
for(int i = 0; i < 26; i++)
cnt[i] += t[cur].sum[i];
return ;
}
query(lc(cur), l, r);
query(rc(cur), l, r);
}

void modify(int cur, int l, int r, int c){
if(t[cur].l > r || t[cur].r < l)
return ;
if(t[cur].l >= l && t[cur].r <= r){
t[cur].clear();
t[cur].sum[c] = t[cur].r - t[cur].l + 1;
t[cur].lazy = c;
return ;
}
push_down(cur);
modify(lc(cur), l, r, c);
modify(rc(cur), l, r, c);
push_up(cur);
}

void print(int cur){
if(t[cur].l == t[cur].r){
for(int i = 0; i < 26; i++)
if(t[cur].sum[i])
putchar('a' + i);
return ;
}
push_down(cur);
print(lc(cur));
print(rc(cur));
}
}t;

int main(){
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
int n = inp();
int q = inp();
scanf("%s", s + 1);
t.build(1, 1, n);
while(q--){
int l = inp();
int r = inp();
memset(cnt, 0, sizeof(cnt));
t.query(1, l, r);
if((r - l + 1) & 1){
int cs = 0, num;
for(int i = 0; i < 26; i++)
if(cnt[i] & 1){
cs++;
num = i;
}
if(cs == 1){
int mid = (l + r) >> 1;
t.modify(1, mid, mid, num);
int cc = 0;
for(int i = 0; i < 26; i++){
if(cnt[i] <= 1)
continue;
int c2 = cc + (cnt[i] >> 1);
t.modify(1, l + cc, l + c2 - 1, i);
t.modify(1, r - c2 + 1, r - cc, i);
cc = c2;
}
}
} else {
int cs = 0, num = -1;
for(int i = 0; i < 26; i++)
if(cnt[i] & 1){
cs++;
num = i;
}
if(cs == 0){
int cc = 0;
for(int i = 0; i < 26; i++){
if(cnt[i] == 0)
continue;
int c2 = cc + (cnt[i] >> 1);
t.modify(1, l + cc, l + c2 - 1, i);
t.modify(1, r - c2 + 1, r - cc, i);
cc = c2;
}
}
}
}
t.print(1);
putchar('\n');
}

 评论