/*wrong:
#include<bits/stdc++.h>
using namespace std;
//#define int long long
#define L(i,l,r) for(int i=l;i<=r;i++)
#define R(i,r,l) for(int i=r;i>=l;i--)
const int N=1e5+10;
int n,m;
char s[N];
struct Node{
int l,r;
int d,lzy;
};
// 每个字母对应的线段树维护某个区间 [l,r] 该字母出现的次数
// 区间求和,区间赋值
struct SEG{
#define ls (u<<1)
#define rs (u<<1|1)
Node tr[N<<2];
void pushup(int u){
tr[u].d=tr[ls].d+tr[rs].d;
}
void build(int u,int l,int r,int opt){
if(l==r){
tr[u]=(Node){l,r,(s[l]-'a')==opt,-1};
return;
}
tr[u]=(Node){l,r,0,-1};
int mid=l+r>>1;
build(ls,l,mid,opt);
build(rs,mid+1,r,opt);
pushup(u);
}
void maketag(int u,int len,int x){
tr[u].d=len*x;
tr[u].lzy=x;
}
void pushdown(int u){
int l=tr[u].l,r=tr[u].r;
int mid=l+r>>1;
if(tr[u].lzy!=-1){
maketag(ls,mid-l+1,tr[u].lzy);
maketag(rs,r-mid,tr[u].lzy);
tr[u].lzy=-1;
}
}
void update(int u,int l,int r,int x){
if(tr[u].l>=l&&tr[u].r<=r){
maketag(u,tr[u].r-tr[u].l+1,x);
return;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) update(ls,l,r,x);
if(r>mid) update(rs,l,r,x);
pushup(u);
}
int query(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r){
return tr[u].d;
}
int res=0;
int mid=tr[u].l+tr[u].r>>1;
pushdown(u);
if(l<=mid) res+=query(ls,l,r);
if(r>mid) res+=query(rs,l,r);
return res;
}
}tr[27];
signed main(){
cin>>n>>m>>(s+1);
L(i,0,25) tr[i].build(1,1,n,i);
while(m--){
int l,r;
cin>>l>>r;
int t[27],cnt=0,ji=-1;
L(i,0,25) t[i]=tr[i].query(1,l,r);
L(i,0,25) if(t[i]&1) cnt++,ji=i;
if(cnt>1) continue;
L(i,0,25) tr[i].update(1,l,r,0);
if(cnt){
t[ji]--;
tr[ji].update(1,l+r>>1,l+r>>1,1); // 出现奇数次的往中间放
}
int nl=l,nr=r;
L(i,0,25){
if(t[i]){
tr[i].update(1,nl,nl+t[i]/2-1,1);
nl+=t[i]/2;
tr[i].update(1,nr,nr-t[i]/2+1,1);
nr-=t[i]/2;
}
}
}
L(i,1,n)
L(j,0,25)
if(tr[j].query(1,i,i))
printf("%c",j+'a');
cout<<endl;
return 0;
}
线段树求调(CF 上说是 RE)。