首页 > 其他分享 >[题解]CF1881G Anya and the Mysterious String

[题解]CF1881G Anya and the Mysterious String

时间:2023-10-19 10:57:46浏览次数:36  
标签:rs int 题解 tree mid read Mysterious query Anya

思路

发现如果一个字符串中有长度大于等于 \(2\) 回文子串,必定有长度为 \(2\) 的回文子串或长度为 \(3\) 的回文子串,并且形如:aaaba

所以考虑用线段树这两种情况。维护一段区间的最左、次左、最右、次右的元素,同时用两个标记变量 \(f_1,f_2\) 分别表示这个区间中是否出现形如 aaaba 的子串即可。

code

#include <bits/stdc++.h>
#define re register

using namespace std;

const int N = 2e5 + 10;
int T,n,q;
char s[N];

inline int read(){
    int r = 0,w = 1;
    char c = getchar();
    while (c < '0' || c > '9'){
        if (c == '-') w = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9'){
        r = (r << 3) + (r << 1) + (c ^ 48);
        c = getchar();
    }
    return r * w;
}

struct seg{
    #define ls(u) (u << 1)
    #define rs(u) (u << 1 | 1)

    struct node{
        int l;
        int r;
        int tag;
        int lc[2];
        int rc[2];
        bool f[2];
    }tr[N << 2];

    inline int Add(int a,int b){
        return (a + b) % 26;
    }

    inline node merge(node a,node b){
        node res = {a.l,b.r,0,{a.lc[0],a.lc[1]},{b.rc[0],b.rc[1]},{a.f[0] | b.f[0],a.f[1] | b.f[1]}};
        if (!~res.lc[1]) res.lc[1] = b.lc[0];
        if (!~res.rc[1]) res.rc[1] = a.rc[0];
        if (~a.rc[0] && ~b.lc[0] && a.rc[0] == b.lc[0]) res.f[0] = true;
        if (~a.rc[1] && ~b.lc[0] && a.rc[1] == b.lc[0]) res.f[1] = true;
        if (~a.rc[0] && ~b.lc[1] && a.rc[0] == b.lc[1]) res.f[1] = true;
        return res;
    }

    inline void calc(int u,int k){
        for (re int i = 0;i <= 1;i++){
            if (~tr[u].lc[i]) tr[u].lc[i] = Add(tr[u].lc[i],k);
            if (~tr[u].rc[i]) tr[u].rc[i] = Add(tr[u].rc[i],k);
        }
        tr[u].tag = Add(tr[u].tag,k);
    }

    inline void pushup(int u){
        tr[u] = merge(tr[ls(u)],tr[rs(u)]);
    }

    inline void pushdown(int u){
        if (tr[u].tag){
            calc(ls(u),tr[u].tag);
            calc(rs(u),tr[u].tag);
            tr[u].tag = 0;
        }
    }

    inline void build(int u,int l,int r){
        tr[u] = {l,r,0,{-1,-1},{-1,-1},{false,false}};
        if (l == r){
            tr[u].lc[0] = tr[u].rc[0] = s[l] - 'a';
            return;
        }
        int mid = l + r >> 1;
        build(ls(u),l,mid);
        build(rs(u),mid + 1,r);
        pushup(u);
    }

    inline void modify(int u,int l,int r,int k){
        if (l <= tr[u].l && tr[u].r <= r){
            calc(u,k);
            return;
        }
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) modify(ls(u),l,r,k);
        if (r > mid) modify(rs(u),l,r,k);
        pushup(u);
    }
    
    inline node query(int u,int l,int r){
        if (l <= tr[u].l && tr[u].r <= r) return tr[u];
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid && r > mid) return merge(query(ls(u),l,r),query(rs(u),l,r));
        if (l <= mid) return query(ls(u),l,r);
        if (r > mid) return query(rs(u),l,r);
    }

    #undef ls
    #undef rs
}tree;

inline void solve(){
    n = read();
    q = read();
    scanf("%s",s + 1);
    tree.build(1,1,n);
    while (q--){
        int op;
        op = read();
        if (op == 1){
            int l,r,x;
            l = read();
            r = read();
            x = read();
            tree.modify(1,l,r,x);
        }
        else{
            int l,r;
            l = read();
            r = read();
            auto res = tree.query(1,l,r);
            if (res.f[0] | res.f[1]) puts("NO");
            else puts("YES");
        }
    }
}

int main(){
    T = read();
    while (T--) solve();
    return 0;
}

最后:祝 CSP-2023 J2/S2 RP += inf。

标签:rs,int,题解,tree,mid,read,Mysterious,query,Anya
From: https://www.cnblogs.com/WaterSun/p/CF1881G.html

相关文章

  • [AGC020F] Arcs on a Circle 题解
    ArcsonaCircle首先,一个非常自然的想法是尝试断环成链。怎么断呢?我们发现,选择最长线段的起点处截断是个非常好的选择,因为不可能有一个线段完全覆盖它。这之后,一个紧接着的想法就是DP。假如把描述中的全部“实点”改成“整点”的话,那么这题是比较trivial的,可以通过随便状压......
  • 洛谷 P4749 [CERC2017] Kitchen Knobs 题解
    KitchenKnobs首先,一个trivial的想法是,因为每个旋钮如果上面的数字并非全部相同则其必有唯一最优位置,故直接扔掉那些全部相同的旋钮,对于剩余的求出其最优位置。明显此位置是一\(0\sim6\)的数。因为是区间同时旋转,所以转成数之后就是区间加同一个数。一个经典套路是差分。这......
  • [ABC207F] Tree Patrolling 题解
    [ABC207F]TreePatrolling弱智DP题,设\(f(i,j,0/1/2)\)表示在点\(i\),子树中有\(j\)个点被覆盖,且\(i\)点自身状态是未被覆盖/被自身覆盖/被某个儿子覆盖,然后树上背包更新就行了。代码:#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintmo......
  • CF1542E2 Abnormal Permutation Pairs (hard version) 题解
    AbnormalPermutationPairs(hardversion)两个限制:字典序小、逆序对大,一个显然的想法就是确保一对关系,统计另一对关系。确保哪一对呢?我们想了想,决定确保字典序小,因为字典序是可以贪心的。具体而言,我们考虑两个排列自第\(i\)位开始出现了不同。这样子,我们便将两个排列各自划......
  • AT_tdpc_tree 木 题解
    木弱智DP题,直接设\(f_i\)表示\(i\)子树内染色的方案数,然后每次合并一个点与它的儿子即可(具体而言,因为儿子间独立,所以方案数就是二项式系数)。需要注意的是因为第一条边可以在任意位置,所以要以每个点为根各DP一次。但是这样每条边会被算两次,所以乘以2的逆元即可。时间......
  • [ARC072E] Alice in linear land 题解
    [ARC072E]Aliceinlinearland首先,一个trivial的想法是记\(f_i\)表示第\(i\)步前离终点的距离,于是\(f_i=\min\Big(f_{j-1},|f_{j-1}-d_i|\Big)\)。然后,我们设\(f_i'\)表示在修改第\(i\)步后,此时离终点的距离。明显,\(f_i'\)可以为任意不大于\(f_i\)的值,因为此时......
  • CF568E Longest Increasing Subsequence 题解
    LongestIncreasingSubsequenceLIS问题有两种主流\(O(n\logn)\)解法,最常见的树状数组法,以及不那么常见的二分法。然后考虑本题,发现一个神奇的思路就是求出LIS后倒序复原出数组。进一步思考后发现,因为本题是LIS(LongestIncreasingSubsequence)而非LNDS(LongestNon-Decr......
  • [AGC046D] Secret Passage 题解
    SecretPassage稍微观察一下就能发现,任一时刻,我们剩下的东西必然是一段定死了的后缀,加上一些可以任意塞位置的0与1。考虑任意一个由上述时刻生成的串,就会发现它与该后缀的最长公共子序列长度即为后缀长度,且还剩余一些0与1。于是考虑模拟最长公共子序列的过程。设\(g_{i,j......
  • Atcoder Beginner Contest 324 G Generate Arrays 题解-Treap
    为了更好的阅读体验,请点击这里题目链接套上平衡树板子就能做的很快的题,然后因为是指针存树,因此交换只需要把序列大小较小的挨个拿出来插到相应的地方即可。复杂度\(O(N\log^2N)\)。但是一定要记住不可以直接使用std::swap交换包含带有指针的类的实例(如代码中的Treap类)!......
  • 精选题解汇总
    Part1比赛题解CF1873CF1203CF1234CF1249Part2难题题解P1124P6346P2198P7974P4814......