题目链接:点击查看

题目大意:给出一个长度为 nnn 的字符串,再给出 mmm 次询问,每次询问需要输出本质不同第 kkk 小的子串的起止位置。如果有多个答案,输出起点最小的那个。强制在线。

题目分析:后缀树的模板题,在后缀树上按照字典序前序遍历维护一下前缀和(子串个数),然后对于每次询问就可以二分查找答案在哪个节点了。

具体难点有两条:

  1. 如何在后缀树上按照字典序遍历
  2. 如何维护每个子串首次出现的位置

对应的解决方案如下:

  1. 根据 parent 树边的性质将子节点排序
  2. 维护 endpos 的极值

那么如何求后缀树呢?其实只需要将字符串反转一下,然后扔到后缀自动机里,此时求出的 parentparentparent 树就是后缀树了。

原理也十分简单,考虑 parentparentparent 树的叶子节点到根节点的一条路径,表示的是一个前缀的所有后缀,反转一下自然就变成了一个后缀的所有前缀,也就是后缀树了。

因为本题需要记录相应子串的首次出现位置,所以可以维护一下反串中每个节点的 endposendposendpos 的最大值用于答案输出。

剩下的就是亿点点坐标转换的细节了,大家可以用样例以及:

abcd
1
0
ans=1 1

这组样例自己调一下,都能调过去的话应该就没有问题了。

代码:

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) (x&-x)
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{T f=1;x=0;char ch=getchar();while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();x*=f;
}
template<typename T>
inline void write(T x)
{if(x<0){x=~(x-1);putchar('-');}if(x>9)write(x/10);putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e5+100;
char s[N];
vector<int>node[N<<1];
int tot,last,endpos[N<<1];
LL sum[N<<1];
int rk[N<<1],dfn;
struct Node
{int ch[26];int fa,len;
}st[N<<1];
inline int newnode()
{tot++;for(int i=0;i<26;i++)st[tot].ch[i]=0;st[tot].fa=st[tot].len=0;endpos[tot]=0;node[tot].clear();return tot;
}
void add(int x)
{int p=last,np=last=newnode();st[np].len=st[p].len+1;while(p&&!st[p].ch[x])st[p].ch[x]=np,p=st[p].fa;if(!p)st[np].fa=1;else{int q=st[p].ch[x];if(st[p].len+1==st[q].len)st[np].fa=q;else{int nq=newnode();st[nq]=st[q]; st[nq].len=st[p].len+1;st[q].fa=st[np].fa=nq;while(p&&st[p].ch[x]==q)st[p].ch[x]=nq,p=st[p].fa;//向上把所有q都替换成nq}}
}
void dfs_pos(int u) {for(auto v:node[u]) {dfs_pos(v);endpos[u]=max(endpos[u],endpos[v]);}
}
void dfs(int u,int fa) {if(u!=1) {dfn++;sum[dfn]=sum[dfn-1]+(st[u].len-st[fa].len);rk[dfn]=u;}vector<pair<char,int>>son;for(auto v:node[u]) {son.push_back({s[endpos[v]-st[u].len],v});}sort(son.begin(),son.end());for(auto it:son) {dfs(it.second,u);}
}
void build() {for(int i=1;i<=tot;i++) {node[st[i].fa].push_back(i);}dfs_pos(1);dfs(1,-1);
}
void init()
{last=1;dfn=tot=0;newnode();
}
int main()
{#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);while(scanf("%s",s+1)!=EOF) {init();int n=strlen(s+1);reverse(s+1,s+1+n);for(int i=1;i<=n;i++) {add(s[i]-'a');endpos[last]=i;}build();int m;scanf("%d",&m);LL l=0,r=0;while(m--) {LL k;scanf("%lld",&k);k=(k^l^r)+1;if(k<=sum[dfn]) {int t=lower_bound(sum+1,sum+1+dfn,k)-sum;int u=rk[t];int len=st[u].len-(sum[t]-k);l=n-endpos[u]+1;r=l+len-1;} else {l=r=0;}printf("%lld %lld\n",l,r);}}return 0;
}

HDU - 5008 Boring String Problem(后缀树求本质不同第k大子串)相关推荐

  1. HDU 5008 Boring String Problem ( 后缀数组求本质不同第k大子串)

    Boring String Problem Zeronera题解 预处理sum数组记录不同字符串的个数,即sum[i] = n- sa[i] + 1 -height[i] + sum[i-1] (n为 ...

  2. hdu 5008 Boring String Problem(后缀数组+rmq)

    题目链接:hdu 5008 Boring String Problem 题意: 给你一个字符串,有q个询问,每次询问该字符串所有的子串中字典序第k小的是哪个串,输出位置,如果有多个位置,输出最靠左的那 ...

  3. HDU - 5008 Boring String Problem(后缀数组+二分)

    题目链接:点击查看 题目大意:给出一个字符串,接下来给出 q 个询问,每次询问字符串中第 k 大的子串,要求输出该字串的左右端点,如果有多个答案,输出左端点最小的一个 题目分析:因为在求出后缀数组后, ...

  4. 2021ICPC(沈阳) - String Problem(后缀树+贪心)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串 sss,对于每个前缀来说,求出字典序最大的子串. 题目分析:看到子串的字典序,感觉能用后缀树来做,参考了一下大佬的赛上代码: 香港中文大 ...

  5. 2021CCPC(桂林) - Suffix Automaton(后缀树+线段树)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的字符串,再给出 qqq 次询问,每次询问需要输出本质不同第 kkk 小的子串的起止位置.如果有多个答案,输出起点最小的那个. 本题规定字符串大小 ...

  6. 求序列中第k大的元素(划分树模板)

    http://acm.hdu.edu.cn/showproblem.php?pid=4251 n个数,求给定区间中间大小的元素的值 Sample Input 5 5 3 2 4 1 3 1 3 2 4 ...

  7. 主席树 ---- LCA(树上第k大)Count on a tree

    题目链接:https://www.spoj.com/problems/COT/en/ 题意: 给你一颗树,问你u,v结点这条路径上第k大是多少. 思路:就是说先将无根树转化为有根树,然后对每一条链建立 ...

  8. 怎么修改数组中指定元素_求数组中第K大的元素

    问题描述 求无序数组int[] nums中第K大的元素. 例如 输入:nums[] = {9,5,8},k = 2 输出:8 输入:nums[] = {3,1,2,4,5,5,6},k = 4 输出: ...

  9. HDU - 5475 An easy problem(线段树)

    题目链接:点击查看 题目大意:给定n次操作和一个m,每次操作后对m取模,每次操作分为两种,初始化当前的数为1: 1 x:当前的数乘上x后输出结果 2 x:当前的数除以第x个操作的数后输出结果 题目分析 ...

最新文章

  1. oracle 不查加锁的记录,oracle 锁查询 select加锁方法
  2. Java并发编程基础--ThreadLocal
  3. XCTF WEB xff_referer
  4. 计算机专业毕业求职,计算机专业毕业生求职简历
  5. 如何为从 1 到 10 万用户的应用程序,设计不同的扩展方案?
  6. php计算经纬度距离,php经纬度计算距离
  7. 基于python的性能测试工具–locust
  8. pycharm操作指北
  9. html基础—页面框架,前端基础——页面架构
  10. 精通JavaScript--06设计模式:结构型
  11. AutoCAD-源泉设计-利器
  12. PR曲线(ROC曲线)是如何画出来的?
  13. 车型代号对照表_车型与VIN代号对照表
  14. MPB:南农韦中组-​根系分泌物调控土壤微生物群落结构和功能的研究方法
  15. 如何有效回复审稿人的意见
  16. 院士如何应对互联网的碎片化和复杂性?道翰天琼认知智能机器人平台API接口大脑为您揭秘。
  17. 双人联机五子棋html代码,双人联机聊天或五子棋游戏设计【高手请进】
  18. 1863: Dinner
  19. 线性代数:置换、转置矩阵和向量空间
  20. 前端面试题(附答案)完善中……

热门文章

  1. 卫生统计学v是什么意思_四川大学华西公共卫生学院报考常见问题答疑
  2. 小说形象特征包括哪些方面_中高考常考题:怎样鉴赏散文中的形象 ?
  3. Nginx解决跨域问题的具体实现
  4. RabbitMQ Topic交换机的作用
  5. 简单了解各种序列化技术-Avro序列化
  6. Java实现消息消费
  7. 使用Lambda优化日志案例
  8. 使用ln -s解决库冲突的问题
  9. 通过RocketMQ的java客户端api进行测试
  10. Lambda省略格式Lambda使用前提