题意: 给一个字符串,有m次操作。每次操作子串[l,r],如果子串能变成回文就把它变成字典序最小的回文,否则不操作。输出最后的字符串。
思路: 如果你知道一个字符串有几个a组成几个b组成...,并且它能够组成回文,那么你就能迅速写出它字典序最小的回文(a先放两边再b这样下去)。所以我们只要用线段树统计好字符串里26个字母的个数就能得出回文,并且按这个回文更新线段树。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <climits>
#include <numeric>
#include <vector>
#define N 100010
int n;
char buf[N];
struct segment{
int l,r,mark,cnt[26];
segment(){memset(cnt,0,sizeof(cnt));mark=-1;}
};
class segTree{
#define lson rt<<1
#define rson rt<<1|1
#define rtl seg[rt].l
#define rtr seg[rt].r
private:
segment seg[N<<2];
public:
void setValue(int c,int rt)
{
memset(seg[rt].cnt,0,sizeof(seg[rt].cnt));
seg[rt].cnt[c]=rtr-rtl+1;
}
void pushup(int rt)
{
for(int i=0;i<26;i++)
seg[rt].cnt[i]=seg[lson].cnt[i]+seg[rson].cnt[i];
}
void pushdown(int rt)
{
if(seg[rt].mark!=-1){
setValue(seg[rt].mark,lson);
setValue(seg[rt].mark,rson);
seg[lson].mark=seg[rt].mark;
seg[rson].mark=seg[rt].mark;
seg[rt].mark=-1;
}
}
void update(int c,int L,int R,int rt)
{
if(L<=rtl && rtr <=R){
seg[rt].mark=c;
setValue(c,rt);
return ;
}
pushdown(rt);
int mid=(rtl+rtr)>>1;
if(L<=mid) update(c,L,R,lson);
if(R>mid) update(c,L,R,rson);
pushup(rt);
}
void query(int cnt[],int L,int R,int rt)
{
if(L<=rtl && rtr <=R){
for(int i=0;i<26;i++)
cnt[i]+=seg[rt].cnt[i];
return ;
}
int mid=(rtl+rtr)>>1;
pushdown(rt);
if(L<=mid) query(cnt,L,R,lson);
if(R>mid) query(cnt,L,R,rson);
}
void build(int l,int r,int rt)
{
rtl=l,rtr=r;
if(l==r){
seg[rt].cnt[buf[l-1]-'a']=1;
return ;
}
int mid=(l+r)>>1;
build(l,mid,lson);
build(mid+1,r,rson);
pushup(rt);
}
void transform(char ans[],int rt)
{
if(rtl==rtr){
for(int i=0;i<26;i++)
if(seg[rt].cnt[i]){
ans[rtl-1]='a'+i;
break;
}
return ;
}
pushdown(rt);
transform(ans,lson);
transform(ans,rson);
}
}T;
bool check(int l,int r,int cnt[])
{
int i,oddsum=0;
for(i=0;i<26;i++)
if(cnt[i]%2) oddsum++;
if(oddsum>1) return false;
if(oddsum!=(r-l+1)%2) return false;
return true;
}
void solve(int L,int R)
{
int i,cnt[26]={0},oddpos=-1,l,r,_l,_r;
T.query(cnt,L,R,1);
if(!check(L,R,cnt)) return ;
for(i=0;i<26;i++){
if(cnt[i]%2){
oddpos=i;
break;
}
}
if(oddpos!=-1)
cnt[oddpos]--;
l=L , _r=R;
for(i=0;i<26;i++){
cnt[i]/=2;
if(cnt[i]){
r=cnt[i]+l-1;
_l=-cnt[i]+_r+1;
T.update(i,l,r,1);
T.update(i,_l,_r,1);
l=r+1;
_r=_l-1;
}
}
if(oddpos!=-1)
T.update(oddpos,l,_r,1);
}
int main()
{
#ifdef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
int m,l,r;
scanf("%d %d",&n,&m);
scanf("%s",buf);
T.build(1,n,1);
while(m--){
scanf("%d %d",&l,&r);
solve(l,r);
}
T.transform(buf,1);
printf("%s\n",buf);
return 0;
}