题目链接:

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;  //把最大值置为0return ;}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);elseupdate(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));elsereturn 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;elsenode[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;
}

线段树+KMP-hdu-4125-Moles相关推荐

  1. hdu 4125 Moles(kmp+树状数组)

    题目链接:hdu 4125 Moles 题意: 给你n个数,让你按键值建一个平衡二叉树,然后奇数为0,偶数为1,然后可以遍历这颗树得到一个欧拉序列,现在给你一个串,问你出现了几次. 题解: 建树的时候 ...

  2. HDU 4125 Moles 线段树+KMP

    题意: 给定n, 下面是1-n的排列. 下面一个二进制子串. 先按给定的排列建出二叉树. 然后遍历树(根->左子树->根->右子树->根) 遍历这个节点时 若权值为奇数入栈一个 ...

  3. HDU 4125 Moles 段树+KMP

    意甲冠军: 特定n, 下面是一个1-n该装置. 下面的二进制字符串. 按给定的建立二叉树安排. 然后遍历树(根->左子树->根->右子树->根) 当遍历节点 如果右值为奇数入栈 ...

  4. HDU 4125 Moles 二叉排序树 树状数组 kmp

    题目链接 题意 将一串数( n≤1e6 n\leq 1e6)依次插入到一棵二叉排序树中, dfs dfs一遍,将经过的每个节点的信息加到一个串尾(如果当前节点为奇数则加 ′1′ '1'否则加 ′0′ ...

  5. 线段树专辑——hdu 1698 Just a Hook

    http://acm.hdu.edu.cn/showproblem.php?pid=1698 这是一个区间染色的问题,对于区间染色问题,通常的方法是在线段树中定义一个cover域,当cover的值为- ...

  6. hdu 4125 Moles

    这几天在做北大出的现场赛题,崩溃. 今天做的11年福州的现场赛题,俩字,呵呵... 好几道都是各种算法糅合啊啊啊啊... 哎 这个题,比较恶心了,DFS不能用系统栈,得自己写,好吧.不算神马.建二叉查 ...

  7. 线段树模板hdu 1754:I Hate It

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  8. 【线段树】HDU 3397 Sequence operation 区间合并

    操作 Change operations: 0 a b change all characters into '0's in [a , b] 1 a b change all characters i ...

  9. HDU 4125 Moles 笛卡尔树 + kmp

    题意:有n(1<=n<=600000)个鼹鼠挖洞,每个鼹鼠有给定权值,挖的洞是一颗二叉树(左边的鼹鼠权值都比当前鼹鼠小,右边的鼹鼠权值比当前鼹鼠大), 也要按照鼹鼠的出场顺序挖洞,在形成的 ...

  10. HDU 4125 Moles 树状数组 + KMP

    这题的重点就在于建树, 题目读懂以后, 就会发现, 树建好以后就是一颗排序二叉树. 于是每次用树状数组二分找该节点的插入点. 树建完以后DFS得到字符串, 由于节点非常多, 于是要手写栈. 字符串得到 ...

最新文章

  1. 微信小程序自定义组件实现
  2. WPF企业内训全程实录(中)
  3. 知识工程.Vs.软件构架,框架,设计模式.
  4. Windows之vue-cli安装和vue项目快速搭建
  5. 年假计算器在线_死亡计算器 和 年龄计算器
  6. 贪心/思维题 UVA 11292 The Dragon of Loowater
  7. django 22、python3.4环境下新建django应用失败报错计算机中丢失python27.dll的解决方法
  8. WinRAR 去除广告
  9. solidworks电气元件3d库_丨部件库丨西门子3RV6电机保护开关
  10. centos host在哪 local_centos怎么查看hostid
  11. 计算机毕业设计论文——国内外文献查找网站
  12. 石家庄地铁路线安排网站的设计
  13. Apache HBase
  14. 关于海报和插画的区别
  15. mysql的reorg_DB2 runstats和reorg操作
  16. 推荐7个免费自学网站提升自我价值必备网站
  17. android bitmap 色温,OpenGL ES 实现图片的饱和度,色温调节
  18. npm -4048报错解决
  19. 中国老婆和韩国老公的故事
  20. 计算机组成原理数据线引脚,计算机组成原理复习题及问题详解.doc

热门文章

  1. java星星随机下落_随机产生星星,单击星星消失
  2. w7计算机管理哪个是显卡,win7怎么看显卡配置以及win7怎么看电脑完整配置
  3. matplotlib画图(一)——线条图
  4. 如何拆笔记本--键盘拆卸
  5. ICML 2022 重思考为图结构数据异常检测设计图神经网络 | 图数据异常节点检测 | 论文解读和代码复现
  6. yahoo邮箱foxmail收发
  7. 春招计算机学校,衡东计算机IT春招学校排名
  8. 产品分析 淘宝、京东、平多多
  9. 认识loadrunner及相关性能参数
  10. 怎么提取音乐中的伴奏?分享一个超好用的方法