传送门


感觉题目讲的很不清楚……

题目意思就是给出一个长度为\(n\)的字符串,求对于\(r=0,1,...,n-1\),求出\(LCP(suffix_p,suffix_q) \geq r\)的无序数对\((p,q)\)的数目,并令一对无序数对的价值为\(val_p \times val_q\),则还要求对于每一个\(r\),所有满足上述条件的无序数对中的最大价值

跟后缀\(LCP\)长度有关,直接上\(SA\)。求出\(sa\)数组和\(height\)数组,我们考虑如何实现对于每一个\(r\)的询问快速求出答案。不妨将\(r\)从大到小求解,那么对于某一个后缀\(sa_k\),满足\(LCP(suffix_{sa_p} , suffix_{sa_k}) \geq r\)的\(p\)一定是一段区间,而且这一段区间随着\(r\)的缩小不断增大。

然后我们考虑如何拓展区间。考虑对于\(height_k=q\),当\(r>q\)的时候\(k\)位置两端的区间不会越过\(k-1\)与\(k\),而当\(r \leq q\)时这两段区间就会合成一段区间。这个显然是可以使用并查集维护的,并且可以比较轻松地在并查集上维护最大价值。

  1. #include<bits/stdc++.h>
  2. #define mid ((l + r) >> 1)
  3. #define lch Tree[x].l
  4. #define rch Tree[x].r
  5. //This code is written by Itst
  6. using namespace std;
  7. inline int read(){
  8. int a = 0;
  9. char c = getchar();
  10. bool f = 0;
  11. while(!isdigit(c) && c != EOF){
  12. if(c == '-')
  13. f = 1;
  14. c = getchar();
  15. }
  16. if(c == EOF)
  17. exit(0);
  18. while(isdigit(c)){
  19. a = (a << 3) + (a << 1) + (c ^ '0');
  20. c = getchar();
  21. }
  22. return f ? -a : a;
  23. }
  24. const int MAXN = 3e5 + 10;
  25. int fa[MAXN] , val[MAXN] , valMax[MAXN][2] , valMin[MAXN][2];
  26. int sa[MAXN] , rk[MAXN] , pot[MAXN] , tp[MAXN << 1] , h[MAXN];
  27. int ind[MAXN] , size[MAXN] , N , maxN = 26;
  28. char s[MAXN];
  29. long long Max , cnt , ans[MAXN][2];
  30. int find(int x){
  31. return fa[x] == x ? x : (fa[x] = find(fa[x]));
  32. }
  33. void Debug(){
  34. for(int i = 1 ; i <= N ; ++i)
  35. cout << sa[i] << ' ';
  36. cout << endl;
  37. for(int i = 1 ; i <= N ; ++i)
  38. cout << ind[i] << ' ';
  39. cout << endl << endl;
  40. }
  41. void input(){
  42. N = read();
  43. scanf("%s" , s + 1);
  44. for(int i = 1 ; i <= N ; ++i){
  45. val[i] = read();
  46. if(val[i] < 0)
  47. valMin[i][0] = val[i];
  48. }
  49. }
  50. void sort(int p){
  51. memset(pot , 0 , sizeof(pot));
  52. for(int i = 1 ; i <= N ; ++i)
  53. ++pot[rk[i]];
  54. for(int i = 1 ; i <= maxN ; ++i)
  55. pot[i] += pot[i - 1];
  56. for(int i = 1 ; i <= N ; ++i)
  57. sa[++pot[rk[tp[i]] - 1]] = tp[i];
  58. memcpy(tp , rk , sizeof(int) * (N + 1));
  59. for(int i = 1 ; i <= N ; ++i)
  60. rk[sa[i]] = rk[sa[i - 1]] + (tp[sa[i]] != tp[sa[i - 1]] || tp[sa[i] + p] != tp[sa[i - 1] + p]);
  61. maxN = rk[sa[N]];
  62. }
  63. bool cmp(int a , int b){
  64. return h[a] < h[b];
  65. }
  66. void init(){
  67. memset(valMax , -0x3f , sizeof(valMax));
  68. Max = -1ll * 0x3f3f3f3f * 0x3f3f3f3f;
  69. for(int i = 1 ; i <= N ; ++i)
  70. rk[tp[i] = i] = s[i] - 'a' + 1;
  71. sort(0);
  72. for(int i = 1 ; i <= N && maxN < N ; i <<= 1){
  73. int cnt = 0;
  74. for(int j = 1 ; j <= i ; ++j)
  75. tp[++cnt] = N - i + j;
  76. for(int j = 1 ; j <= N ; ++j)
  77. if(sa[j] > i)
  78. tp[++cnt] = sa[j] - i;
  79. sort(i);
  80. }
  81. for(int i = 1 ; i <= N ; ++i){
  82. if(rk[i] == 1)
  83. continue;
  84. int t = rk[i];
  85. h[t] = max(0 , h[rk[i - 1]] - 1);
  86. while(s[sa[t] + h[t]] == s[sa[t - 1] + h[t]])
  87. ++h[t];
  88. ind[t] = t;
  89. }
  90. sort(ind + 2 , ind + N + 1 , cmp);
  91. for(int i = 1 ; i <= N ; ++i){
  92. fa[i] = i;
  93. size[i] = 1;
  94. valMax[i][0] = val[i];
  95. }
  96. }
  97. inline void merge(int x , int y){
  98. fa[x] = y;
  99. int num[4] = {valMax[x][0] , valMax[x][1] , valMax[y][0] , valMax[y][1]};
  100. sort(num , num + 4);
  101. valMax[y][0] = num[3];
  102. valMax[y][1] = num[2];
  103. Max = max(Max , 1ll * valMax[y][0] * valMax[y][1]);
  104. num[0] = valMin[x][0];
  105. num[1] = valMin[x][1];
  106. num[2] = valMin[y][0];
  107. num[3] = valMin[y][1];
  108. sort(num , num + 4);
  109. valMin[y][0] = num[0];
  110. valMin[y][1] = num[1];
  111. if(1ll * valMin[y][0] * valMin[y][1])
  112. Max = max(Max , 1ll * valMin[y][0] * valMin[y][1]);
  113. cnt -= 1ll * size[x] * (size[x] - 1) / 2 + 1ll * size[y] * (size[y] - 1) / 2;
  114. size[y] += size[x];
  115. cnt += 1ll * size[y] * (size[y] - 1) / 2;
  116. }
  117. void work(){
  118. int p = N;
  119. for(int i = N - 1 ; i >= 0 ; --i){
  120. while(p > 1 && h[ind[p]] == i){
  121. merge(find(sa[ind[p]]) , find(sa[ind[p] - 1]));
  122. --p;
  123. }
  124. if(cnt){
  125. ans[i][0] = cnt;
  126. ans[i][1] = Max;
  127. }
  128. }
  129. }
  130. void output(){
  131. for(int i = 0 ; i <= N - 1 ; ++i)
  132. cout << ans[i][0] << ' ' << ans[i][1] << '\n';
  133. }
  134. int main(){
  135. input();
  136. init();
  137. work();
  138. output();
  139. return 0;
  140. }

Luogu2178 NOI2015 品酒大会 SA、并查集的更多相关文章

  1. bzoj4199: [Noi2015]品酒大会 (并查集 && 后缀数组)

    据说用后缀自动机 + dp也能做 然而并不会 后缀数组的做法呢 就是先建个后缀数组,求出height值,此时如果直接找,复杂度是n ^ 2的,肯定会超时. 但是height大的值是不会对小的产生影响的 ...

  2. [NOI2015]品酒大会(SA数组)

    [NOI2015]品酒大会 题目描述 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发"首席品酒家"和" ...

  3. luogu2178/bzoj4199 品酒大会 (SA+单调栈)

    他要求的就是lcp(x,y)>=i的(x,y)的个数和a[x]*a[y]的最大值 做一下后缀和,就只要求lcp=i的了 既然lcp(x,y)=min(h[rank[x]+1],..,[h[ran ...

  4. BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]

    4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...

  5. [UOJ#131][BZOJ4199][NOI2015]品酒大会 后缀数组 + 并查集

    [UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...

  6. 【BZOJ4199】[Noi2015]品酒大会 后缀数组+并查集

    [BZOJ4199][Noi2015]品酒大会 题面:http://www.lydsy.com/JudgeOnline/wttl/thread.php?tid=2144 题解:听说能用SAM?SA默默 ...

  7. [NOI2015] 品酒大会 - 后缀数组,并查集,STL,启发式合并

    [NOI2015] 品酒大会 Description 对于每一个 \(i \in [0,n)\) 求有多少对后缀满足 LCP 长度 \(\le i\) ,并求满足条件的两个后缀权值乘积的最大值. So ...

  8. [UOJ#131][BZOJ4199][NOI2015]品酒大会

    [UOJ#131][BZOJ4199][NOI2015]品酒大会 试题描述 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品酒家”和“首席猎手”两个 ...

  9. 洛谷 P2178 [NOI2015]品酒大会 解题报告

    P2178 [NOI2015]品酒大会 题目描述 一年一度的"幻影阁夏日品酒大会"隆重开幕了.大会包含品尝和趣味挑战 两个环节,分别向优胜者颁发"首席品酒家"和 ...

随机推荐

  1. VUE CLI 3.0 项目引入 Mock.js

    mockjs 官网:http://mockjs.com/ 之前没有使用过 mockjs 的同学,请参考官网文档,数据生成规则和方法的调用都有详细说明. 一.通过npm安装依赖包 1. 进入到项目目录, ...

  2. TCP协议学习总结

    1.TCP协议通过三次握手建连接,四次挥手断连接. 2.TCP的定时器都有哪些? 做什么用途? 3.TCP的慢启动是什么意思? 4.TCP的快速重传是什么意思?

  3. Handle的原理(Looper、Handler、Message三者关系)

    转载请注明出处:http://blog.csdn.net/lowprofile_coding/article/details/72580044 介绍 前面的内容对Handler做了介绍,也讲解了如何使 ...

  4. (网页)logback的使用和logback.xml详解(转)

    转自博客园:行走在云端的愚公: 一.logback的介绍 Logback是由log4j创始人设计的另一个开源日志组件,官方网站: http://logback.qos.ch.它当前分为下面下个模块: ...

  5. 使用VSTS的Git进行版本控制(六)——拉取请求

    使用VSTS的Git进行版本控制(六)--拉取请求 在将代码合并到主干之前,拉取请求让团队对特性分支的更改提供反馈.审阅人可以通过建议修改留下评论,并投票批准或拒绝代码. 任务1:在Visual St ...

  6. MagicApp说明

    title: MagicApp说明 date: 2017-12-06 05:41:00 tags: IT 技术 MagicApp是日常处理的程序,协助进行日常工作处理 批量重命名模块 说明 该模块是根 ...

  7. Ubuntu16下配置支持Windows访问的samba共享

    一.安装Ubuntu samba服务器 $ sudo apt-get install samba $ sudo apt-get install smbclient # Linux客户端测试用 二.创建 ...

  8. Pinyin4j实战

    package com.haiyisoft.innovationcenter.pinyin; import org.junit.Test; import net.sourceforge.pinyin4 ...

  9. [20180316]为什么不使用INDEX FULL SCAN (MIN/MAX).txt

    [20180316]为什么不使用INDEX FULL SCAN (MIN/MAX).txt --//链接:http://www.itpub.net/thread-2100456-1-1.html.自己 ...

  10. [20171120]11g select for update skip locked.txt

    [20171120]11g select for update skip locked.txt --//11G在select for update遇到阻塞时可以通过skipped locked跳过阻塞 ...