这段代码是一个基于Trie树和线段树的程序。以下是代码的大致解释:
首先,定义了一些常量和变量用于存储输入和结果。
然后,定义了一个用于将字符映射为数值的函数Calc,它根据字符返回一个对应的数值。
接下来,定义了两个结构体Str和Range,用于存储字符串和区间的信息。
然后,定义了一个Trie结构体,包含一个表示子节点的数组和表示范围的Range变量。
接着,定义了一个Insert函数,用于向Trie树中插入字符串。该函数通过递归地插入字符,并更新范围信息。
然后,定义了一个Query函数,用于查询Trie树中以给定字符串为前缀的子树的范围。该函数也是通过递归地查询字符来实现的。
接下来,定义了一个SegmentTree结构体,用于表示线段树中的节点,其中只存储了一个表示区间和的变量。
然后,定义了一些宏用于简化代码。
接着,定义了一些辅助函数,包括PushUp用于更新线段树中节点的值,Updata用于更新线段树中某个位置的值,Query用于查询线段树中某个区间的和。
然后,定义了一个Change结构体,用于表示修改线段树中节点值的操作。
接下来,定义了一些与上述结构体和函数相关的辅助函数。
然后,定义了主函数main。在主函数中,首先读取输入的n和m。
然后,使用循环读取n个字符串,并将它们存储在s和t数组中,并对t数组进行反转。
接下来,根据字符串s的字典序对s和t数组进行排序,并为每个字符串分配一个唯一的id。
然后,创建两个空的Trie树root1和root2。
然后,使用循环将字符串s和t插入到对应的Trie树中。
接下来,根据要查询的字符串s1和s2,查询Trie树root1和root2中以s1和s2为前缀的子树的范围。
然后,根据查询结果生成一组操作,并将它们存储在c数组中。
接下来,对操作数组c按照高度从小到大进行排序。
然后,使用循环执行操作数组中的操作,并更新结果数组answer。
最后,使用循环输出结果数组answer。
这段代码的功能是查询给定字符串的前缀和后缀在字符串数组中出现的次数,并输出结果。
输入示例:
插入代码复制代码
2 3
AUGC
AGC
G C
AU C
A C
输出示例:
插入代码复制代码
0
1
1
请注意,输出示例是根据输入示例假设的情况而生成的,实际运行时的结果可能会有所不同。
下面是这篇解释的代码(无注释版)
/*
做法
先建两棵Trie树
一棵A树正着存 找前缀
一棵B树倒着存 找后缀
同过找A树中所有以s为前缀的子树
和B树中所有反串T为后缀以下的
*/
#include<bits/stdc++.h>
using namespace std;
const int MAXN=3e5+5;
int n,m;
string s1,s2;
bool visit[MAXN];
int answer[MAXN];
int Calc(char x){//大概是哈希 把字符转为数值
if(x=='U') return 1;
else if(x=='G') return 2;
else if(x=='C') return 3;
return 0;
}
struct Str{
string s;
int id;
}s[MAXN],t[MAXN];
bool Cmp(Str a,Str b){
return a.s<b.s;
}
struct Range{
int l,r;
Range(int left=0,int right=0){
l=left;
r=right;
}
} null(0,0);
struct Trie{
int son[4];
Range r;
}trie[MAXN*20];
int trie_cnt=0;
#define SON(n) trie[now].son[n]
void Insert(int time,string &s,int &now,int deep=0){
if(!now){//如果这个点未到过
trie[now=++trie_cnt].r.l=time;
trie[now].r.r=time;
}else{
trie[now].r.r=time;
}
if(deep==s.size()){
return;
}
Insert(time,s,SON(Calc(s[deep])),deep+1);
}
Range Query(string &s,int now,int deep=0){
if(!now){
return null;
}
if(deep==s.size()){
return trie[now].r;
}
return Query(s,SON(Calc(s[deep])),deep+1);
}
struct SegmentTree{
int sum;
}sgt[MAXN*4];
#define LSON (now<<1)
#define RSON (now<<1|1)
#define MIDDLE ((left+right)>>1)
#define LEFT LSON,left,MIDDLE
#define RIGHT RSON,MIDDLE+1,right
#define NOW now_left,now_right
void PushUp(int now){
sgt[now].sum=sgt[LSON].sum+sgt[RSON].sum;
}
void Updata(int place,int now=1,int left=1,int right=n){
if(place<left||right<place){
return;
}
if(left==right){
sgt[now].sum++;
return;
}
Updata(place,LEFT);
Updata(place,RIGHT);
PushUp(now);
}
int Query(int now_left,int now_right,int now=1,int left=1,int right=n){
if(now_right<left||right<now_left){
//在范围外
return 0;
}
if(now_left<=left&&right<=now_right){
return sgt[now].sum;
}
return Query(NOW,LEFT)+Query(NOW,RIGHT);
}
#undef LSON
#undef RSON
#undef MIDDLE
#undef LEFT
#undef RIGHT
#undef NOW
struct Change{
int high,left,right,id,val;
void Make(int h,int l,int r,int i,int v){
high=h;
left=l;
right=r;
id=i;
val=v;
}
}c[MAXN];
bool Cmp_c(Change a,Change b){
return a.high<b.high;
}
int main(){
scanf("%d%d",&n,&m);
char ch=getchar();
for(int i=1;i<=n;i++){
getline(cin,s[i].s);
s[i].id=i;
t[i]=s[i];
if(t[i].s.size()-1){
for(int j=0;j<=t[i].s.size()/2-1;j++){
swap(t[i].s[j],t[i].s[t[i].s.size()-1-j]);
}
}
}
sort(s+1,s+1+n,Cmp);
for(int i=1;i<=n;i++){
t[s[i].id].id=i;
}
sort(t+1,t+1+n,Cmp);
int root1=0,root2=0;
for(int i=1;i<=n;i++){
Insert(i,s[i].s,root1);
Insert(i,t[i].s,root2);
}
int l,r;
Range ans1,ans2;
for(int i=1;i<=m;i++){
cin>>s1>>s2;
if(s2.size()-1){
for(int j=0;j<=s2.size()/2-1;j++){
swap(s2[j],s2[s2.size()-j-1]);
}
}
ans1=Query(s1,root1);
ans2=Query(s2,root2);
if(ans1.l&&ans2.l){
if(ans2.l-1){
c[i*2-1].Make(ans2.l-1,ans1.l,ans1.r,i,-1);
}
c[i*2].Make(ans2.r,ans1.l,ans1.r,i,1);
}
}
sort(c+1,c+2*m+1,Cmp_c);
int now=1;
for(int i=0;i<=n;i++){
Updata(t[i].id);
while(c[now].high==i){
answer[c[now].id]+=c[now].val*Query(c[now].left,c[now].right);
now++;
}
}
for(int i=1;i<=m;i++){
printf("%d\n",answer[i]);
}
return 0;
}
/*
2 3
AUGC
AGC
G C
AU C
A C
*/