对于长度为x的平方串,只需要每隔x做一个关键点,然后对相邻关键点做lcp和lcs就可以找出每一个平方串。

sa或者hash+二分都是可以的

找出平方串的区间,下面要实现的操作就是实现区间中x和x+le合并。

用倍增维护一下并查集,开log个并查集,若x,y在第i个并查集里被并起来,意味着x..x+2i−1x..x+2^i-1x..x+2i−1与y..y+2i−1y..y+2^i-1y..y+2i−1是相等的。

每次并两个区间的时候,先拆成两个完整的2幂区间,然后合并一个2幂区间的时候,看他在当前并查集里是否并在一起,假如没有就先并起这层,然后分开两层,继续往下(有点像线段树那样)

每往下走两个点都会并一次,因此这个结构的复杂度是O(n log)

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>using namespace std;
const int N = 1e6 + 10, W = 1e9 + 7;
typedef unsigned long long ll;
int n, T, a[N], fa[N];
int lg[N];struct SA{int sa[N], rk[N], h[N], cnt[N];int nsa[N], nrk[N];int le[N][20];void reset() {for(int i = 1; i <= n + n + n; i++) sa[i]=rk[i]=h[i]=0;}int lcp(int a,int b) {a = rk[a], b = rk[b]; if (a > b) swap(a, b);b--;int sz = lg[b - a + 1];return min(le[a][sz], le[b - (1 << sz) + 1][sz]);}void build(int *a) {for(int i = 1; i <= n; i++) cnt[i] = 0;for(int i = 1; i <= n; i++) rk[i] = a[i], cnt[a[i]] ++;for(int i = 1; i <= n; i++) cnt[i] += cnt[i - 1];for(int i = 1; i <= n; i++) sa[cnt[a[i]]--] = i;for(int m = 1; m <= n; m <<= 1) {for(int i = 1; i <= n; i++) cnt[i] = 0;for(int i = 1; i <= n; i++) cnt[rk[i]]++;for(int i = 1; i <= n; i++) cnt[i] += cnt[i - 1];for(int i = n; i; i--) {int x = sa[i] - m;if (x > 0) nsa[cnt[rk[x]] --] = x;}for(int i = n - m + 1; i <= n; i++) nsa[cnt[rk[i]]--] = i;for(int i = 1; i <= n; i++) sa[i] = nsa[i];for(int i = 1; i <= n; i++) {nrk[sa[i]] = nrk[sa[i - 1]] + (rk[sa[i - 1]] != rk[sa[i]] || rk[sa[i - 1] + m] != rk[sa[i] + m]);}for(int i = 1; i <= n; i++) rk[i] = nrk[i];}for(int i = 1; i <= n; i++) {int nex = sa[rk[i] + 1];h[rk[i]] = max(0, h[rk[i - 1]] - 1);while (a[nex + h[rk[i]]] == a[i + h[rk[i]]]) h[rk[i]]++;}for(int i = 1; i <= n; i++) {for(int j = 0; j < 20; j++) le[i][j] = -1e9;}for(int i = 1; i <= n; i++) le[i][0] = h[i];for(int i = 1; i < 20; i++) {for(int j = 1; j <= n; j++) {le[j][i] = min(le[j][i - 1], le[j + (1 << i - 1)][i - 1]);}}//check?// for(int i = 1; i <= n; i++) {//    for(int j = sa[i]; j <= n; j++) printf("%d ",a[j]);//  printf("\n");// }// printf("\n");}
} suf, pre;int b[N];
int w;
pair<int,int> px[N];struct dsu{int fa[N];int gf(int x) {return fa[x] == 0 ? x : fa[x] = gf(fa[x]);}void merge(int a,int b) {fa[gf(a)] = gf(b);}void reset() {for(int i = 1; i <= n + n; i++) fa[i] = 0;}
} d[20];int qcnt;
void qmerge(int x,int y,int sz) {if (d[sz].gf(x) != d[sz].gf(y)) {d[sz].merge(x,y);if (sz == 0) qcnt++;else {qmerge(x, y, sz - 1);qmerge(x + (1 << sz - 1), y + (1 << sz - 1), sz - 1);}}
}void qjmerge(int al,int ar,int bl,int br) {int sz = lg[ar - al + 1];qmerge(al, bl, sz);qmerge(ar - (1 << sz) + 1, br - (1 << sz) + 1, sz);
}int main(){freopen("endless.in","r",stdin);freopen("endless.out","w",stdout);for(int i = 2; i <= 3e5; i++) lg[i] = lg[i >> 1] + 1;int z = 0;for(cin>>T;T;T--){if ((++z) == 2318) {int kkk = T;}scanf("%d",&n), w = n / 2;for(int i = 0; i < 20; i++) d[i].reset();for(int i = 1; i <= n; i++) scanf("%d",&a[i]), b[n - i + 1] = a[i];for(int i = n + 1; i <= n + n; i++) a[i] = b[i] = 0;for(int i = 1; i <= w; i++) {scanf("%d", &px[i].first);px[i].second = i;}suf.reset(), pre.reset();pre.build(a);suf.build(b);sort(px + 1, px + 1 + w);long long ans = 0;for(int e = 1; e <= w; e++) {int len = px[e].second;qcnt = 0;for(int ka = 1; ka + len <= n; ka += len) {int kb = ka + len;int la = min(len, suf.lcp(n - ka + 1, n - kb + 1));int lb = min(len, pre.lcp(ka, kb));if (la + lb < len + 1) continue;int zb = ka - la + 1, yb = kb + lb - 1;yb -= len;qjmerge(zb, yb, zb + len, yb + len);}ans += (ll)qcnt * px[e].first;}printf("%lld\n",ans);}
}

jzoj6152. 【GDOI2019Day2模拟2019.4.29】Endless (倍增维护并查集,平方串)相关推荐

  1. [NOI2018] 归程(线段树维护并查集的可持久化/kruskal重构树,倍增+dijkstra最短路)

    [NOI2018] 归程 description solution1 code1 solution2 code description 题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要 ...

  2. 【XSY2485】MST(最小生成树+倍增lca+并查集)

    题面 Description 给定一个nnn个点mmm条边的连通图,保证没有自环和重边.对于每条边求出,在其他边权值不变的情况下,它能取的最大权值,使得这条边在连通图的所有最小生成树上.假如最大权值为 ...

  3. 【2018.5.19】模拟赛之四-ssl2435 航空公司【并查集,二分】

    正题 题目大意 有n个点,给出坐标,选择所有距离在k之内的边要求联通所有点,求最小的k. 解题思路 垃圾解法 用二分答案然后加并查集求是否联通. 时间复杂度:O(mlogn)O(mlogn)O(mlo ...

  4. 【2018.5.12】模拟赛之三-ssl2415 连通块【并查集】

    正题 题目大意 在一个n*n的棋盘上进行m此操作.在一个格子上放一个黑或白的棋子.多个相连的同色棋子形成一个连通块,求每次操作后求连通块数. 解题思路 并查集表示连通,然后每次扩展,如果有同色的就连通 ...

  5. [JZOJ3385] [NOIP2013模拟] 黑魔法师之门 解题报告(并查集)

    Description 经过了16个工作日的紧张忙碌,未来的人类终于收集到了足够的能源.然而在与Violet星球的战争中,由于Z副官的愚蠢,地球的领袖applepi被邪恶的黑魔法师Vani囚禁在了Vi ...

  6. 2019.7.29学习整理python

    2019.7.29学习整理python 1.变量 1.1什么是变量? 是变化的量.描述变化的世间万物的状态 1.2变量的组成 变量名:变量名用来引用变量值,但凡需要用变量值,都需要通过变量名. 赋值符 ...

  7. 18天精读掌握《费曼物理学讲义卷一》 第13天 2019/6/29

    18天精读掌握<费曼物理学讲义卷一> 第13天 2019/6/29 1. 18日掌握<费曼物理学讲义>卷一计划概览 2. 今日学习成果 3. 今日时间表 4.Atimelogg ...

  8. 15天精读掌握《高德纳:具体数学》 第3天 2019.5.29

    15天精读掌握<高德纳:具体数学> 第3天 2019/5.29 1. 15日掌握算法导论计划概览 2. 今日学习成果 3. 今日时间表 4.Atimelogger截图 今天是 2年修完清华 ...

  9. 专业导论-课后总结-2019.11.29

    专业导论-课后总结-2019.11.29 在经过学习有关计算机的硬件组成之后,我们进入了计算机的另一个重要组成部分--计算机的网络.如果要我说出计算机与它最开始的不同的话,我会说,网络.网络使得计算机 ...

  10. MRT数据恢复取证软件下载 2019.1.29更新

    MRT数据恢复取证软件下载 2019.1.29更新 修改时间:2018-05-17 22:42:29 浏览次数:2453次 MRT数据恢复软件更新日志   2019年1月29日 MRT 2130版本, ...

最新文章

  1. zoj 1698 Easier Done Than Said?
  2. Kaggle债务违约预测冠军经验分享
  3. ubuntu终端彻底删除软件
  4. Codeforces Round #655 (Div. 2) E. Omkar and Last Floor 区间dp + 巧妙的状态设计
  5. 乐乐茶签约帆软软件,打造新式茶饮数字化管理新标杆
  6. PHP配置限制文件大小上传
  7. 两个月学习Python的胡言乱语
  8. PPT,要你好看(全彩)pdf
  9. IOS xib 和storyboard的区别
  10. Java餐厅点餐系统【附源码报告】
  11. 《使用Nsis打包安装程序》
  12. csv文件超过104万数据怎么办
  13. 固实压缩文件容易损坏_请慎重使用固实压缩文件
  14. mysql的软件卸载不了,控制台也卸载不了的问题
  15. Matlab如何进行利用离散傅里叶逆变换iDFT 从频谱恢复时域信号
  16. 万丈高楼平地起,勿在浮沙筑高台--论程序员基础知识的重要性
  17. 计算机本体应用,本体评估方法研究综述
  18. 工信部电信投诉网站入口
  19. 鼠友题库每日百题(三)
  20. c++ 操作hadoop

热门文章

  1. linux txt转化vcf命令,【9.2更新】Vcf转换工具(Excel、TXT转Vcf 和 Vcf转Excel)
  2. 网易云音乐基于用户的推荐系统
  3. 超级表格pk王者农药,今天你五杀了么?
  4. matlab解韩信点兵问题,小学数学题目巧解—韩信点兵问题
  5. 双轨制二叉树节点对象
  6. tf.contrib.layers.embed_sequence()函数
  7. Kafka:增加Topic的分区数
  8. 入夏短裤热 教你怎么穿
  9. 关于手机-Android版本-基带版本,连续点击六次进入工厂模式。自定义版本点五次动态隐藏显示某应用。
  10. stm32 simulink 快速计算 Timmer定时器需要的预分频PSC和自动重载ARR