CF 240F TorCoder

线段树

题目名称有意思- -

用线段树维护区间各个字母出现次数即可。 然后做回文串就贪心从小往大放。

#include<cstdio>
#include<cstring>
#define N 100005
#define A 27
using namespace std;
namespace runzhe2000
{
    char str[N];
    int v[A];
    struct seg
    {
        int v[A], lazy;
    }t[N<<2];
    void pushup(int x)
    {
        for(int i = 0; i < A; i++)
            t[x].v[i] = t[x<<1].v[i] + t[x<<1|1].v[i];
    }
    void pushdown(int x, int l, int r)
    {
        if(t[x].lazy == -1) return; int mid = (l+r)>>1;
        t[x<<1].lazy = t[x<<1|1].lazy = t[x].lazy;
        memset(t[x<<1].v, 0, sizeof t[x<<1].v);
        memset(t[x<<1|1].v, 0, sizeof t[x<<1|1].v);
        t[x<<1].v[t[x].lazy] = mid-l+1;
        t[x<<1|1].v[t[x].lazy] = r-mid;
        t[x].lazy = -1;
    }
    void query(int x, int l, int r, int ql, int qr)
    {
        if(ql <= l && r <= qr) {for(int i = 0; i < A; i++) v[i] += t[x].v[i]; return;}
        pushdown(x,l,r);
        int mid = (l+r)>>1;
        if(ql <= mid) query(x<<1,l,mid,ql,qr);
        if(mid <  qr) query(x<<1|1,mid+1,r,ql,qr);
    }
    void modi(int x, int l, int r, int ql, int qr, int v)
    {
        if(ql <= l && r <= qr)
        {
            memset(t[x].v, 0, sizeof t[x].v);
            t[x].v[v] = r-l+1; t[x].lazy = v;
            return;
        }
        pushdown(x,l,r);
        int mid = (l+r)>>1;
        if(ql <= mid) modi(x<<1,l,mid,ql,qr,v);
        if(mid <  qr) modi(x<<1|1,mid+1,r,ql,qr,v);
        pushup(x);
    } 
    void build(int x, int l, int r)
    {
        t[x].lazy = -1;
        if(l == r)
        {
            memset(t[x].v, 0, sizeof t[x].v);
            t[x].v[str[l] - 'a'] ++; return;
        }
        int mid = (l+r)>>1;
        build(x<<1,l,mid); build(x<<1|1,mid+1,r);
        pushup(x);
    }
    void main()
    {
        int n, m; scanf("%d%d",&n,&m);
        scanf("%s",str+1);
        build(1,1,n);
        for(int l, r; m--; )
        {
            scanf("%d%d",&l,&r);
            memset(v,0,sizeof v);
            query(1,1,n,l,r);
            int oddcnt = 0;
            for(int i = 0; i < A; i++)
                if(v[i]&1) oddcnt++;
            if((r-l+1)&1)// odd
            {
                if(oddcnt != 1) continue;
            }
            else
            {
                if(oddcnt) continue;
            }
            for(int i = 0; i < A; i++)
            {
                if(v[i]) 
                    modi(1,1,n,l,l+v[i]/2-1,i), l += v[i]/2,
                    modi(1,1,n,r-v[i]/2+1,r,i), r -= v[i]/2;
            }
            for(int i = 0; i < A; i++)
                if(v[i] & 1)
                    modi(1,1,n,l,r,i);
        }
        for(int i = 1; i <= n; i++)
        {
            memset(v,0,sizeof v);
            query(1,1,n,i,i);
            for(int i = 0; i < A; i++)
                if(v[i]) {printf("%c",i+'a'); break;}
        }
    }
}
int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    runzhe2000::main(); 
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值