题意:有n(1<=n<=600000)个鼹鼠挖洞,每个鼹鼠有给定权值,挖的洞是一颗二叉树(左边的鼹鼠权值都比当前鼹鼠小,右边的鼹鼠权值比当前鼹鼠大),
也要按照鼹鼠的出场顺序挖洞,在形成的二叉树按照中序遍历顺序奇数偶数(1,0)得到01序列,问01序列中给定的序列出现多少次。
题解:笛卡尔树,k(SBT)为鼹鼠的权值,a(堆)为鼹鼠的编号,排序后O(n)建树之后kmp即可。递归会RE,手动模拟栈。
Sure原创,转载请注明出处
#include <iostream> #include <cstdio> #include <memory.h> #include <algorithm> using namespace std; const int maxn = 600002; const int maxm = 7002; struct P { int k,a; bool operator < (const P &other) const { return k < other.k; } }mole[maxn]; struct T { int l,r,fa; }tree[maxn]; int next[maxm],stack[maxn],state[maxn]; char str[maxm],list[maxn * 3]; int n,tot,top; void init() { memset(tree,0,sizeof(tree)); memset(state,0,sizeof(state)); tot = top = 0; return; } void read() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&mole[i].k); mole[i].a = i; } sort(mole + 1 , mole + n + 1); scanf("%s",str); return; } void rotate(int x) { int p = tree[x].fa; int l = tree[x].l; if(p == tree[tree[p].fa].l) { tree[tree[p].fa].l = x; } else { tree[tree[p].fa].r = x; } tree[x].fa = tree[p].fa; tree[x].l = p; tree[p].fa = x; tree[p].r = l; if(l) tree[l].fa = p; return; } void dfs(int st) { stack[top++] = st; while(top) { int cur = stack[top-1]; list[tot++] = (mole[cur].k & 1) + '0'; if(++state[cur] == 3) { top--; continue; } if(state[cur] == 1) { if(tree[cur].l) stack[top++] = tree[cur].l; else state[cur]++; } if(state[cur] == 2) { if(tree[cur].r) stack[top++] = tree[cur].r; else state[cur]++; } if(state[cur] == 3) top--; } return; } void make() { tree[0].r = 1; int rightmost = 1; for(int i=2;i<=n;i++) { tree[rightmost].r = i; tree[i].fa = rightmost; rightmost = i; while(tree[i].fa && mole[i].a < mole[tree[i].fa].a) rotate(i); } dfs(tree[0].r); list[tot] = '\0'; return; } void getnext(char *s) { int len=strlen(s); for(int i=0;i<=len;i++) { next[i] = 0; } next[0] = -1; int j=-1; for(int i=0;i<len;) { if(j==-1||s[i]==s[j]) { i++; j++; next[i]=j; } else j=next[j]; } return; } int kmp(char a[],char b[]) { int count=0; getnext(b); int lena = strlen(a); int lenb = strlen(b); int j=0,i=0; while(i<lena && j<lenb) { if(j==-1 || b[j]==a[i]) { j++; i++; } else j=next[j]; if(j == lenb) { count++; j = next[j]; } } return count; } int main() { int cas; scanf("%d",&cas); for(int i=1;i<=cas;i++) { printf("Case #%d: ",i); init(); read(); make(); printf("%d\n",kmp(list,str)); } return 0; }