题意:N只编号1-N的鼹鼠打洞,第i只编号为a[i],编号不重复。打的洞的样子符合以a[i]为值,以下标为插入顺序的二叉搜索树。现在从根出发,存在左子树则先走左子树,否则往右走,每经过一个洞(结点),如果这个洞的值是奇数,就记录1,否则记录0,得到的dfs序列是01串S。注意是dfs序列不是中序遍历得到的序列,每个点最多被经过3次:root->lson...lson->root->rson...rson->root.
给定一个串T,问T在S中出现多少次。
求出S之后KMP就好惹。
关键:某个点a[i]的父亲是 左边的数中 比它小的数中最大的值L 或者 比它大的数的最小值R。
L和R都不存在,a[i]是根
仅L不存在,a[i]是R的左儿子
仅R不存在,a[i]是L的右儿子
都存在则L的右儿子和R的左儿子必有一个为空,a[i]就放在空的那个地方。
可以用set求L,R,但是我写会T;
线段树求L,R+读入挂 2938ms/3000ms ,不加会T
笛卡尔树1719ms
笛卡尔树看结点的key满足二叉搜索树,看结点的value满足堆(按具体实现分为小顶堆or大顶堆,此题小顶堆)
a[i]为key,i为value,则value满足早点到的一定最浅,key满足二叉搜索树。
S,T匹配用kmp;注意这个二叉搜索树可能是一条链,dfs序列递归求可能会爆栈,用栈模拟即可√。
线段树:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
const int maxn=6e5+5;
int t,n,stop,a[maxn];
char S[maxn*5],T[7005];
int L[maxn<<2],R[maxn<<2];
int stk[maxn],top;
#define lson (t<<1)
#define rson (t<<1|1)
void build(int t,int l,int r){
if(l==r){
L[t]=-1;R[t]=1e9;return;
}
int mid=l+r>>1;
build(lson,l,mid);build(rson,mid+1,r);
L[t]=-1;R[t]=1e9;
}
void update(int t,int l,int r,int pos){
if(l==r){
L[t]=R[t]=l;return;
}
int mid=l+r>>1;
if(pos<=mid) update(lson,l,mid,pos);
else update(rson,mid+1,r,pos);
L[t]=max(L[lson],L[rson]);
R[t]=min(R[lson],R[rson]);
}
int queryL(int t,int l,int r,int pos){
if(r<=pos) return L[t];
int mid=l+r>>1;
if(pos<=mid) return queryL(lson,l,mid,pos);
else return max(L[lson],queryL(rson,mid+1,r,pos));
}
int queryR(int t,int l,int r,int pos){
if(l>=pos) return R[t];
int mid=l+r>>1;
if(pos<=mid) return min(queryR(lson,l,mid,pos),R[rson]);
else return queryR(rson,mid+1,r,pos);
}
int lchild[maxn],rchild[maxn],fa[maxn];
void dfs(int u){
stk[top++]=u;
while(top){
int u=stk[top-1];
S[stop++]=(u&1)?'1':'0';
if(lchild[u]){
stk[top++]=lchild[u];lchild[u]=0;
}else if(rchild[u]){
stk[top++]=rchild[u];rchild[u]=0;
}else{
top--;
}
}
S[stop]='\0';
}
int nt[7000+5];
char b[10001];
//参数为模板串和next数组
//字符串均从下标0开始
//参数为模板串和next数组
//字符串均从下标0开始
void kmp_next()
{
nt[0]=0;
for(int i=1,j=0,m=strlen(T);i<m;i++)
{
while(j&&T[i]!=T[j])j=nt[j-1];
if(T[i]==T[j])j++;
nt[i]=j;
}
}
int kmp()
{
kmp_next();
int ans=0,sn=strlen(S),tn=strlen(T);
for(int i=0,j=0;i<sn;i++)
{
while(j&&S[i]!=T[j])j=nt[j-1];
if(S[i]==T[j])j++;
if(j==tn)
ans++;
}
return ans;
}
inline char nc() {
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}inline int _read() {
char ch = nc(); int sum = 0;
while (!(ch >= '0'&&ch <= '9'))ch = nc();
while (ch >= '0'&&ch <= '9')sum = sum * 10 + ch - 48, ch = nc();
return sum;
}
inline void _sread(){
char ch = nc();int p=0;
while (!(ch >= '0'&&ch <= '9'))ch = nc();
while (ch >= '0'&&ch <= '9')T[p++] =ch, ch = nc();
T[p]='\0';
}
int main()
{
t=_read();int kase=0;
while(t--){
n=_read();
int root=-1;
stop=0;
build(1,1,n);
for(int i=1;i<=n;i++) lchild[i]=0,rchild[i]=0;
for(int i=1;i<=n;i++){
a[i]=_read();
int l=queryL(1,1,n,a[i]),r=queryR(1,1,n,a[i]);
if(l==-1&&r==1e9) root=a[i];
else if(l==-1){
lchild[r]=a[i];fa[a[i]]=r;
}else if(r==1e9){
rchild[l]=a[i];fa[a[i]]=l;
}else{
if(!lchild[r]) lchild[r]=a[i],fa[a[i]]=r;
else rchild[l]=a[i],fa[a[i]]=l;
}
update(1,1,n,a[i]);
}
_sread();
stop=0;
dfs(root);
// printf("S=%s\n",S);
int ans=kmp();
printf("Case #%d: %d\n",++kase,ans);
}
return 0;
}
笛卡尔树:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <map>
using namespace std;
const int N=6e5+5;
int t,n,x;
int fa[N],ls[N],rs[N];
int stk[N],top,stop;
char S[N*5],T[7005];
void dfs(int u){
stk[top++]=u;
while(top){
int u=stk[top-1];
S[stop++]=(u&1)?'1':'0';
if(ls[u]){
stk[top++]=ls[u];ls[u]=0;
}else if(rs[u]){
stk[top++]=rs[u];rs[u]=0;
}else{
top--;
}
}
S[stop]='\0';
}
int nt[7000+5];
char b[10001];
//参数为模板串和next数组
//字符串均从下标0开始
//参数为模板串和next数组
//字符串均从下标0开始
void kmp_next()
{
nt[0]=0;
for(int i=1,j=0,m=strlen(T);i<m;i++)
{
while(j&&T[i]!=T[j])j=nt[j-1];
if(T[i]==T[j])j++;
nt[i]=j;
}
}
int kmp()
{
kmp_next();
int ans=0,sn=strlen(S),tn=strlen(T);
for(int i=0,j=0;i<sn;i++)
{
while(j&&S[i]!=T[j])j=nt[j-1];
if(S[i]==T[j])j++;
if(j==tn)
ans++;
}
return ans;
}
int root;
struct node{
int id,v;
bool operator < (const node &b)const{
return v<b.v;
}
}e[N];
int main(){
scanf("%d",&t);
int kase=0;
while(t--){
stop=top=0;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&e[i].v),e[i].id=i;
memset(ls,0,sizeof(ls));
memset(rs,0,sizeof(rs));
memset(fa,0,sizeof(fa));
sort(e+1,e+n+1);
stk[0]=0;
for(int i = 1; i <= n; i ++){
while(top && e[stk[top]].id > e[i].id)
ls[i] = stk[top], top --;
fa[i] = stk[top];
fa[ls[i]] = i;
if(fa[i]){
rs[fa[i]] = i;
}
else{
root=i;
}
stk[++ top] = i;
}
scanf("%s",T);
stop=top=0;
dfs(root);
// printf("%s\n",S);
int ans=kmp();
printf("Case #%d: %d\n",++kase,ans);
root=0;
}
return 0;
}