线段树+KMP-hdu-4125-Moles
题目链接:
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相关推荐
- hdu 4125 Moles(kmp+树状数组)
题目链接:hdu 4125 Moles 题意: 给你n个数,让你按键值建一个平衡二叉树,然后奇数为0,偶数为1,然后可以遍历这颗树得到一个欧拉序列,现在给你一个串,问你出现了几次. 题解: 建树的时候 ...
- HDU 4125 Moles 线段树+KMP
题意: 给定n, 下面是1-n的排列. 下面一个二进制子串. 先按给定的排列建出二叉树. 然后遍历树(根->左子树->根->右子树->根) 遍历这个节点时 若权值为奇数入栈一个 ...
- HDU 4125 Moles 段树+KMP
意甲冠军: 特定n, 下面是一个1-n该装置. 下面的二进制字符串. 按给定的建立二叉树安排. 然后遍历树(根->左子树->根->右子树->根) 当遍历节点 如果右值为奇数入栈 ...
- HDU 4125 Moles 二叉排序树 树状数组 kmp
题目链接 题意 将一串数( n≤1e6 n\leq 1e6)依次插入到一棵二叉排序树中, dfs dfs一遍,将经过的每个节点的信息加到一个串尾(如果当前节点为奇数则加 ′1′ '1'否则加 ′0′ ...
- 线段树专辑——hdu 1698 Just a Hook
http://acm.hdu.edu.cn/showproblem.php?pid=1698 这是一个区间染色的问题,对于区间染色问题,通常的方法是在线段树中定义一个cover域,当cover的值为- ...
- hdu 4125 Moles
这几天在做北大出的现场赛题,崩溃. 今天做的11年福州的现场赛题,俩字,呵呵... 好几道都是各种算法糅合啊啊啊啊... 哎 这个题,比较恶心了,DFS不能用系统栈,得自己写,好吧.不算神马.建二叉查 ...
- 线段树模板hdu 1754:I Hate It
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- 【线段树】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 ...
- HDU 4125 Moles 笛卡尔树 + kmp
题意:有n(1<=n<=600000)个鼹鼠挖洞,每个鼹鼠有给定权值,挖的洞是一颗二叉树(左边的鼹鼠权值都比当前鼹鼠小,右边的鼹鼠权值比当前鼹鼠大), 也要按照鼹鼠的出场顺序挖洞,在形成的 ...
- HDU 4125 Moles 树状数组 + KMP
这题的重点就在于建树, 题目读懂以后, 就会发现, 树建好以后就是一颗排序二叉树. 于是每次用树状数组二分找该节点的插入点. 树建完以后DFS得到字符串, 由于节点非常多, 于是要手写栈. 字符串得到 ...
最新文章
- 微信小程序自定义组件实现
- WPF企业内训全程实录(中)
- 知识工程.Vs.软件构架,框架,设计模式.
- Windows之vue-cli安装和vue项目快速搭建
- 年假计算器在线_死亡计算器 和 年龄计算器
- 贪心/思维题 UVA 11292 The Dragon of Loowater
- django 22、python3.4环境下新建django应用失败报错计算机中丢失python27.dll的解决方法
- WinRAR 去除广告
- solidworks电气元件3d库_丨部件库丨西门子3RV6电机保护开关
- centos host在哪 local_centos怎么查看hostid
- 计算机毕业设计论文——国内外文献查找网站
- 石家庄地铁路线安排网站的设计
- Apache HBase
- 关于海报和插画的区别
- mysql的reorg_DB2 runstats和reorg操作
- 推荐7个免费自学网站提升自我价值必备网站
- android bitmap 色温,OpenGL ES 实现图片的饱和度,色温调节
- npm -4048报错解决
- 中国老婆和韩国老公的故事
- 计算机组成原理数据线引脚,计算机组成原理复习题及问题详解.doc