洛谷P2282

本文介绍了一种使用C++实现的字符串处理算法,通过构建哈希表和段树,解决字符级和区间查询问题。重点讲解了hs_make函数用于构造哈希表,以及Segment_tree结构用于高效查询和更新区间。应用实例涉及字符串中特定子串的匹配和区间范围内的优化搜索。
摘要由CSDN通过智能技术生成

这题有点难度

不多说,上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
unsigned int h[500000],pow[500000];
char st[500000];
int f[500000],n,l0[500000],r0[500000];
void hs_make(char st[],unsigned int h[])
{
    pow[0]=1;
    for(int i=1;i<=strlen(st);i++)h[i]=h[i-1]*233+st[i-1]-48,pow[i]=pow[i-1]*233;
}
unsigned int hs(int l,int r){return h[r]-h[l-1]*pow[r-l+1];}
int xy(int l1,int r1,int l2,int r2)
{
    if(r1-l1+1<r2-l2+1)return 1;
    if(r1-l1+1>r2-l2+1)return 0;
    int l=0,r=r1-l1+1,mid;
    while(l<r)
    {
        mid=(l+r+1)>>1;
        if(hs(l1,l1+mid-1)==hs(l2,l2+mid-1))l=mid;
        else r=mid-1;
    }
    return l!=r1-l1+1&&st[l1+l-1]<st[l2+l-1];
}
struct Segment_tree
{
    int a[200000],tag[200000];
    void build(int rot,int lt,int rt)
    {
        tag[rot]=a[rot]=0;
        if(lt==rt)return;
        int mid=(lt+rt)>>1;
        build(rot<<1,lt,mid),build(rot<<1|1,mid+1,rt);
    }
    void pushdown(int rot,int lt,int rt)
    {
        if(tag[rot])
        {
            int t=tag[rot];tag[rot]=0;
            tag[rot<<1]=max(t,tag[rot<<1]),tag[rot<<1|1]=max(t,tag[rot<<1|1]);
            a[rot<<1]=max(t,a[rot<<1]),a[rot<<1|1]=max(t,a[rot<<1|1]);
        }
    }
    int query(int rot,int lt,int rt,int q)
    {
        if(lt==rt)return a[rot];
        int mid=(lt+rt)>>1;
        pushdown(rot,lt,rt);
        if(q<=mid)return query(rot<<1,lt,mid,q);
        else return query(rot<<1|1,mid+1,rt,q);
    }
    void update(int rot,int lt,int rt,int lq,int rq,int w)
    {
        if(lt>rq||rt<lq)return;
        if(lt>=lq&&rt<=rq)
        {
            a[rot]=max(a[rot],w),tag[rot]=max(tag[rot],w);
            return;
        }
        int mid=(lt+rt)>>1;
        pushdown(rot,lt,rt);
        update(rot<<1,lt,mid,lq,rq,w),update(rot<<1|1,mid+1,rt,lq,rq,w);
        a[rot]=max(a[rot<<1],a[rot<<1|1]);
    }
}seg;
int main()
{
    while(scanf("%s",st)==1)
    {
        hs_make(st,h);n=strlen(st);
        for(int i=1;i<=n;i++)if(st[i-1]=='0')l0[i]=l0[i-1];else l0[i]=i;r0[n+1]=n+1;
        for(int i=n;i>=1;i--)if(st[i-1]=='0')r0[i]=r0[i+1];else r0[i]=i;
        seg.build(1,0,n);
        for(int i=0;i<n;i++)
        {
            int fi=seg.query(1,0,n,i);
            int t=r0[i+1]+i-r0[fi];
            if(!xy(r0[fi],i,r0[i+1],t))t++;
            if(t<=n)seg.update(1,0,n,t,n,i+1);
        }

        int fn=seg.query(1,0,n,n);
        seg.build(1,0,n);
        seg.update(1,0,n,l0[fn-1]+1,n,n);
        for(int i=fn;i>1;i--)
        {
            int fi=seg.query(1,0,n,i);
            int t=l0[max(i-1+r0[i]-fi-1,0)]+1;
            if(!xy(r0[t],i-1,r0[i],fi))t=r0[t]+1;

            seg.update(1,0,n,t,i-1,i-1);
        }
        int pos=seg.query(1,0,n,1);
        for(int i=1;i<=n;i++)
        {
            putchar(st[i-1]);
            if(i==pos&&i!=n)putchar(','),pos=seg.query(1,0,n,i+1);
        }
        putchar(10);
    }
}

//当然,你可以用万能头文件

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值