线段树+KMP-hdu-4125-Moles

来源:互联网 发布:2017java就业形势 编辑:程序博客网 时间:2024/05/19 16:02

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=4125

题目意思:

给1~n组成的n个数,按输入顺序插入到平衡二叉树中,现在按1~n从小到大的顺序从根开始访问节点,每遇到一个节点i,如果i为奇数则序列+‘1’,如果i为偶数则序列+‘0’,这样得到一个序列res,给一个01序列s,求s在res中出现的次数,可以重叠。

解题思路:

首先要明白平衡二叉树的三个性质:

1、对于新插入的节点,其父亲要么是比自己大的最小的那个,或比自己小的最大的那个。

2、先序遍历为从小到大的顺序。

3、先序遍历回到根节点一共要访问2*n-1次节点。因为有n-1条边,一共有2*n-2个度,对于每个节点来说它的度数即为它的访问次数,而根节点进来的时候要加一个度,所以就是2*n-1次。

问题就转化成了,给一个数,求出在它之前的数序列中小于它的最大值或大于它的最小值。而这个问题可以用线段树维护,每个区间维护该区间已经放了数的最大值和最小值,如果查小于va的最大值,如果va>mid,则直接返回max(左区间的最大值,查右边)。同理查询大于va的最小值。

这个问题解决后,就是按先序顺序遍历,求出走的序列res.

最后KMP求出s在res中出现的次数,因为可以重复,所有每找到一个完全匹配串后,模式串下标跳到其的next值处。

代码:

#include<iostream>#include<cmath>#include<cstdio>#include<cstdlib>#include<string>#include<cstring>#include<algorithm>#include<vector>#include<map>#include<set>#include<stack>#include<list>#include<queue>#include<ctime>#define eps 1e-6#define INF 0x3f3f3f3f#define PI acos(-1.0)#define ll __int64#define lson l,m,(rt<<1)#define rson m+1,r,(rt<<1)|1#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;#define Maxn 610000int n;struct Inte{    int mi,ma; //线段树维护区间的最大值和最小值}inte[Maxn*4];struct Node //静态存储,左右孩子节点{    int l,r;}node[Maxn];void pushup(int v) //向上更新{    inte[v].mi=min(inte[v<<1].mi,inte[v<<1|1].mi);    inte[v].ma=max(inte[v<<1].ma,inte[v<<1|1].ma);}void build(int l,int r,int rt){    if(l==r) //建树    {        inte[rt].mi=INF; //把最小值置为无穷大,表示不存在        inte[rt].ma=0;  //把最大值置为0        return ;    }    int m=(l+r)>>1;    build(lson);    build(rson);    pushup(rt);}void update(int l,int r,int rt,int va) //单点更新{    if(l==r)    {        inte[rt].mi=inte[rt].ma=va;        return ;    }    int m=(l+r)>>1;    if(va<=m)        update(lson,va);    else        update(rson,va);    pushup(rt);}int query1(int l,int r,int rt,int va) //查询小于va的最大值{   if(l==r)        return inte[rt].ma;    int m=(l+r)>>1;    if(va<=m) //不需要查询右区间了      return query1(lson,va);    else    //左区间的直接返回后比较        return max(inte[rt<<1].ma,query1(rson,va));}int query2(int l,int r,int rt,int va)//查询大于va的最小值{    if(l==r)        return inte[rt].mi;    int m=(l+r)>>1;    if(va<=m)        return min(inte[rt<<1|1].mi,query2(lson,va));    else        return query2(rson,va);}char res[Maxn<<1];int s,cnt;char bb[7500];void dfs(int cur) //按先序遍历搜{    res[++cnt]=(cur&1)?'1':'0'; //走到改点    if(node[cur].l) //如果有左儿子    {        dfs(node[cur].l);        if(node[cur].r) //如果有右儿子        {            res[++cnt]=(cur&1)?'1':'0';//访问完左子树,回到它自己            dfs(node[cur].r); //再访问右子树        }        res[++cnt]=(cur&1)?'1':'0';//回到自己        return ;    }    if(node[cur].r) //只有右子树    {        dfs(node[cur].r);        res[++cnt]=(cur&1)?'1':'0'; //访问完右子树后回到自己    }}int next[7500],nn;void getnext() //模式串求next数组{    int j=0;    next[1]=0;    for(int i=2;i<=nn;i++)    {        while(j>0&&bb[j+1]-bb[i])            j=next[j];        if(bb[j+1]==bb[i])            j++;        next[i]=j;    }    return ;}int KMP() //{    int j=0;    int ans=0;    for(int i=1;i<=cnt;i++)    {        while(j>0&&bb[j+1]-res[i])            j=next[j];        if(bb[j+1]==res[i])            j++;        if(j==nn)        {            ans++;            j=next[j];        }    }    return ans;}int main(){    int t;    scanf("%d",&t);    for(int ca=1;ca<=t;ca++)    {        scanf("%d",&n);        build(1,n,1); //建树        scanf("%d",&s);        update(1,n,1,s);//插到叶子        cnt=0;        memset(node,0,sizeof(node));        for(int i=2;i<=n;i++)        {            int a,al,ar;            scanf("%d",&a);            al=query1(1,n,1,a); //小于a的最大值            ar=query2(1,n,1,a); //大于a的最小值            if(!al) //不存在小于a的最大值                node[ar].l=a; //那么只能是以大于a的最小值作为父亲            else if(ar==INF)  //不存在自己作为左儿子的父亲                node[al].r=a; //那么只可能是自己是右儿子的父亲            else            {                if(node[al].r) //已经有了                    node[ar].l=a;                else                    node[al].r=a;            }            update(1,n,1,a);//加到线段树中        }     /*   for(int i=1;i<=n;i++)            printf("i:%d l:%d r:%d\n",i,node[i].l,node[i].r);*/        cnt=0;        dfs(s);        scanf("%s",bb+1);        nn=strlen(bb+1);        getnext();        int ans=KMP();        printf("Case #%d: %d\n",ca,ans);    }   return 0;}




原创粉丝点击