前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >洛谷P4555 [国家集训队]最长双回文串(manacher 线段树)

洛谷P4555 [国家集训队]最长双回文串(manacher 线段树)

作者头像
attack
发布2019-03-04 16:14:38
3470
发布2019-03-04 16:14:38
举报

题意

题目链接

Sol

我的做法比较naive。。首先manacher预处理出以每个位置为中心的回文串的长度。然后枚举一个中间位置,现在要考虑的就是能覆盖到i - 1的回文串中 中心最靠左的,和能覆盖到i+1中 中心最靠右的,算一下答案取个max。

线段树维护一下区间min, max。标记永久化炒鸡好写

代码语言:javascript
复制
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 10, INF = 1e9 + 10;
char s[MAXN];
int len[MAXN], N, ans[MAXN];
template<typename A, typename B> inline void chmax(A &x, B y) {
    x = x < y ? y : x;
}
template<typename A, typename B> inline void chmin(A &x, B y) {
    x = x < y ? x : y;
}
int root, ls[MAXN], rs[MAXN], mn[MAXN], mx[MAXN], tot;
void Max(int &k, int l, int r, int ql, int qr, int v) {
    if(!k) k = ++tot, mn[k] = INF;
    if(ql <= l && r <= qr) {chmax(mx[k], v); return ;}
    int mid = l + r >> 1;
    if(ql <= mid) Max(ls[k], l, mid, ql, qr, v);
    if(qr  > mid) Max(rs[k], mid + 1, r, ql, qr, v);
}
void Min(int &k, int l, int r, int ql, int qr, int v) {
    if(!k) k = ++tot, mn[k] = INF;
    if(ql <= l && r <= qr) {chmin(mn[k], v); return ;}
    int mid = l + r >> 1;
    if(ql <= mid) Min(ls[k], l, mid, ql, qr, v);
    if(qr  > mid) Min(rs[k], mid + 1, r, ql, qr, v);
}
int QueryMx(int k, int l, int r, int p) {
    int ans = mx[k];
    if(l == r) return ans;
    int mid = l + r >> 1;
    if(p <= mid) chmax(ans, QueryMx(ls[k], l, mid, p));
    else chmax(ans, QueryMx(rs[k], mid + 1, r, p));
    return ans;
}
int QueryMn(int k, int l, int r, int p) {
    int ans = mn[k];
    if(l == r) return ans;
    int mid = l + r >> 1;
    if(p <= mid) chmin(ans, QueryMn(ls[k], l, mid, p));
    else chmin(ans, QueryMn(rs[k], mid + 1, r, p));
    return ans;
}
void trans() {
    static char tmp[MAXN];
    for(int i = 1; i <= N; i++) {
        tmp[2 * i - 1] = s[i];
        tmp[2 * i] = '#';
    }
    memcpy(s, tmp, sizeof(s));
    N = (N << 1) - 1;
    int mx = 0, id = 0;
    for(int i = 1; i <= N; i++) {
        ans[i] = (mx > i ? min(mx - i, ans[id * 2 - i]) : 1);
        while(s[i - ans[i]] == s[i + ans[i]]) ans[i]++;
        if(i + ans[i] > mx) mx = i + ans[i], id = i;
        Max(root, 1, N, i - ans[i] + 1, i, i);
        Min(root, 1, N, i, i + ans[i] - 1, i);
    }
}
int main() {
    scanf("%s", s + 1);
    N = strlen(s + 1);
    trans();
    int ans = 0;
    for(int i = 2; i <= N; i += 2) {
        chmax(ans, (i - 1 - QueryMn(root, 1, N, i - 1)) + 1 + (QueryMx(root, 1, N, i + 1) - i - 1) + 1);
    }
    cout << ans;
    return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-02-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 题意
  • Sol
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档