P5768
对于每个字符串,将其转换成二进制串的形式,每 \(8\) 位表示一个数,且每个串都有一个长度数值 \(L_i\),表示需匹配的位数。
给定 \(n\) 次操作, 操作有两种:
- 插入操作:添加题目给出的掩码长度为 \(L_i\) 的串 \(S\)。
- 查询操作:询问给出的串 \(S\) 在 \(\left[ L,R \right]\) 次插入操作时的字符串匹配时匹配情况变化了几次。
很明显可以用 01trie 维护。
对于每个添加的操作,就将其拆分为 01 串的形式插入 01trie 即可。
至于查询的操作,题目直接明说了用差分,即 \(\left[L,R \right]\) 可以通过 \(\left[1,R \right]-\left[1,L \right]\) 求出。
稍加思考可知匹配的过程能类比单调栈的操作。
就是在 01trie 树上查询时维护一个单调栈:
- 如果当前标记在范围之内,就将栈顶所有时间更晚的标记弹出,再将当前节点入栈。
- 最后结果就是单调栈中的元素个数。
#include <bits/stdc++.h>
using namespace std;const int N=3e6;
int R(){
int x=0;char ch=getchar();while(ch<'0'||ch>'9')ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48);return x;
}void W(int x){if(x>9)W(x/10);putchar(x%10+'0');}
int n,t[N][2],u,c,len,l,r,p[N],tot,f[N],cnt,mi,x,sum,g;char o;
void ip(){for(int j=0,k;j<4;++j){k=R();for(int v=7;v>=0;v--)p[j*8+v]=k%2,k>>=1;}return ;}
void in(){u=0;for(int i=0;i<len;i++){if(!t[u][p[i]])t[u][p[i]]=++tot;u=t[u][p[i]];}f[u]=++cnt;}
int q(int x){
u=0;stack <int> s;
for(int i=0;i<32;i++){
if(!t[u][p[i]])break;u=t[u][p[i]];
if(f[u]&&f[u]<=x){g=f[u];while(s.size()&&g<s.top())s.pop();s.push(g);}
}return s.size();
}int main(){
n=R();for(int i=1;i<=n;i++){
cin>>o;ip();
if(o=='A')len=R(),in();
else l=R(),r=R(),W(q(r)-q(l-1)),puts("");
}return 0;
}