小H和遗迹
时间:2020-08-08
本文章向大家介绍小H和遗迹,主要包括小H和遗迹使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
解:这个题满足一个结论,假设我们当前要比较字符串A和字符串B是不是满足的,假设l1为字符串开头位置到第一个‘#’的前缀,s1为字符串倒序中到最后一个'#‘的后缀。
同理l2和s2.如果字符串A和字符串B是满足题目条件的,那么l1和l2中,肯定有一个是另外一个的前缀。s1和s2中,肯定有一个是另外一个的后缀.
首先需要建立两颗trie树,正序一颗,后序一颗。对于每一个字符串,我们保存当前前缀中第一个'#'之前的前一个坐标x1和当前后缀中最后一个'#'后面的第一个点的坐标x2,然后建图保存x1->x2。
当前这个人的贡献 就是 后序trie树上这个节点v的祖先节点中已经储存了多少人 + 这个节点所代表的子树中已经储存了多少人。正好对应了当前这个后缀是别人的后缀 以及 别人的后缀 是 当前这个后缀 的后缀 这两种情况。
具体的代码实现:
对后序字典序跑一个dfs序,因为需要用到区间的信息。每一次查询的时候,对于当前 后序trie树上这个节点v的祖先节点中已经储存了多少人 的相对应的信息,
可以开一个树状数组维护这个节点到根节点的人的个数。对于 这个节点所代表的子树中已经储存了多少人 这个信息,我们需要另外再开一个树状数组维护这个区间的信息(如果用一个的话会算重),这个区间对答案的贡献就是以当前节点所代表的的子树中有多少人... trie不是很熟悉...题解参考
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e6+9; char s[maxn]; int id(char s){ return s-'a'; } struct tire{ int cnt; int _next[maxn][26]; int insert(char s[]){ int p=0; for(int i=0;s[i];i++){ if(s[i]=='#')break; if(!_next[p][id(s[i])]){ _next[p][id(s[i])]=++cnt; } p=_next[p][id(s[i])]; } return p; } }T1,T2; struct BIT{ int bit[maxn]; int n=1e6; void add(int x,int y){ while(x<=n){ bit[x]+=y; x+=(x&-x); } } ll query(int x){ ll ans=0; while(x){ ans+=bit[x]; x-=(x&-x); } return ans; } }T3,T4; vector<int>G[maxn]; int dfn; int be[maxn],en[maxn]; void dfs1(int u){ be[u]=++dfn; for(int i=0;i<26;i++){ if(T1._next[u][i]){ dfs1(T1._next[u][i]); } } en[u]=dfn; } ll ans=0; void dfs2(int u){ for(int i=0;i<G[u].size();i++){ int v=G[u][i]; ans+=T3.query(be[v]); T3.add(be[v],1); T3.add(en[v]+1,-1); ans+=T4.query(en[v])-T4.query(be[v]); T4.add(be[v],1); } for(int i=0;i<26;i++){ if(T2._next[u][i]){ dfs2(T2._next[u][i]); } } for(int i=0;i<G[u].size();i++){ int v=G[u][i]; T3.add(be[v],-1); T3.add(en[v]+1,1); T4.add(be[v],-1); } } int main(){ int n;scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%s",s); int len=strlen(s); int x=T1.insert(s); reverse(s,s+len); int y=T2.insert(s); G[y].push_back(x); } dfs1(0); dfs2(0); printf("%lld\n",ans); return 0; }
原文地址:https://www.cnblogs.com/sweetlittlebaby/p/13460647.html
- 在Python中用一个长短期记忆网络来演示记忆
- CDA数据分析师学习之路第3期 | Spark RDD的转换操作举例
- 通过Temboo实现从Arduino获取雅虎天气信息
- 自动化模式中的MySQL
- 通过Pandas实现快速别致的数据分析
- R语言中的非线性分类
- 用SPSS做数据分析?先弄懂SPSS的基础知识吧
- 学习笔记CB001:NLTK库、语料库、词概率、双连词、词典
- 时序列数据库武斗大会之 OpenTSDB 篇
- 应当使用 SQLite 的五个原因
- Apache Spark作为编译器:深入介绍新的Tungsten执行引擎
- DC/OS 的安装与部署
- Go语言实践:从新手入门到上线真实的小型服务所遇到的那些坑
- 4个简单的数据管理技巧
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 第37期:从头学二叉搜索树(面试常考)
- Jupyter 工具的安装与使用方法,jupyter运行python代码演示,好用的python编辑器推荐!
- Nginx相关配置与操作
- Python 技术篇-全局与当前socket超时连接时间设置方法实例演示,查看socket超时连接时间
- 给 JDK 报了一个 P4 的 Bug,结果居然……
- Python 套接字-判断socket服务端有没有关闭的方法实例演示,查看socket运行状态
- docker安装logstash
- Rook Operator 源码分析(1) - osd 启动的流程
- Python 技术篇-利用pyqt5库监听剪切板变动,clipboard.dataChanged.connect()剪切板监听
- 关于MySQL server has gone away
- PyQt5 技术篇-在clipboard.dataChanged.connect()里如何写入剪切板示例演示,pyqt5监听剪切板变动并写入剪切板内容
- 去除WordPress链接中出现的index.php
- MySQL 语法问题:You can‘t specify target table ‘xxx‘ for update in FROM clause. 原因及解决方法
- 配置 prometheus-operator 报警规则
- SQL语句查询出的数据进行字符串拼接,oracle批量删除数据库用户实例演示