Kefa and Watch 【CodeForces - 580E】【双值哈希hash+线段树】

题目链接

  题意不难,给你一段长度为N的字符串,接下来就是有两种操作:一是更新一段区间让它们的值相同;二是问这个查询的区间是否符合f(i)==f(i+d),就是是否以d为周期长度。

思路

  确实想了挺久的,首先是字符串,这里就需要用到哈希的方式来处理,一开始哈希没弄好,错了,后来再重做时加上了取mod的操作然后就过了,还有,如何判断它是一个以d为周期长度的字符串呢?就利用f(i)==f(i+d)不就可以了吗,但是查询区间有长度[l, r],所以我们可以查询[l, r-d]与[l+d, r]是否相等不就是满足条件了,还有一件事,题目中说道1 ≤ d ≤ r - l + 1,但是d==(r-l+1)的时候刚哈就是满区间,所以肯定是个以d为周期长度的字符串了。

 

完整代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const ull Hash1=131, Hash2=233;
const ull mod=1e9+7;
const int maxN=1e5+5;
int N, M, Q;
ull ba1[maxN], ba2[maxN], val_1[10][maxN], val_2[10][maxN];
int lazy[maxN<<2];
char s[maxN];
struct node
{
    ull sum1, sum2;
    int l, r;
    node(ull a=0, ull b=0, int c=0, int d=0):sum1(a), sum2(b), l(c), r(d) {}
}tree[maxN<<2];
void pre_did()      //预处理
{
    ba1[0]=ba2[0]=1;
    for(int i=1; i<maxN; i++)
    {
        ba1[i]=ba1[i-1] * Hash1 %mod;
        ba2[i]=ba2[i-1] * Hash2 %mod;
    }
    for(int i=0; i<10; i++) val_1[i][0]=val_2[i][0]=0;
    for(int i=0; i<10; i++)
    {
        for(int j=1; j<maxN; j++)
        {
            val_1[i][j]=( val_1[i][j-1] * Hash1 %mod+i )%mod;
            val_2[i][j]=( val_2[i][j-1] * Hash2 %mod+i )%mod;
        }
    }
}
void pushup(int rt)
{
    int lenr = tree[rt<<1|1].r - tree[rt<<1|1].l+1;
    tree[rt].sum1 =( tree[rt<<1].sum1 * ba1[lenr] + tree[rt<<1|1].sum1 )%mod;
    tree[rt].sum2 =( tree[rt<<1].sum2 * ba2[lenr] + tree[rt<<1|1].sum2 )%mod;
}
void buildTree(int rt, int l, int r)
{
    tree[rt].l=l;   tree[rt].r=r;   lazy[rt]=-1;
    if(l==r)
    {
        tree[rt].sum1=tree[rt].sum2=s[l]-'0';
        return;
    }
    int mid=( l + r )>>1;
    buildTree(rt<<1, l, mid);
    buildTree(rt<<1|1, mid+1, r);
    pushup(rt);
}
void pushdown(int rt)
{
    if(lazy[rt]!=-1)
    {
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        tree[rt<<1].sum1 = val_1[lazy[rt]][tree[rt<<1].r-tree[rt<<1].l+1];
        tree[rt<<1].sum2 = val_2[lazy[rt]][tree[rt<<1].r-tree[rt<<1].l+1];
        tree[rt<<1|1].sum1 = val_1[lazy[rt]][tree[rt<<1|1].r-tree[rt<<1|1].l+1];
        tree[rt<<1|1].sum2 = val_2[lazy[rt]][tree[rt<<1|1].r-tree[rt<<1|1].l+1];
        lazy[rt]=-1;
    }
}
void update(int rt, int l, int r, int ql, int qr, int val)
{
    if(ql<=l && qr>=r)
    {
        lazy[rt] = val;
        tree[rt].sum1 = val_1[val][tree[rt].r-tree[rt].l+1];
        tree[rt].sum2 = val_2[val][tree[rt].r-tree[rt].l+1];
        return;
    }
    pushdown(rt);
    int mid=(l + r)>>1;
    if(ql>mid) update(rt<<1|1, mid+1, r, ql, qr, val);
    else if(qr<=mid) update(rt<<1, l, mid, ql, qr, val);
    else
    {
        update(rt<<1, l, mid, ql, mid, val);
        update(rt<<1|1, mid+1, r, mid+1, qr, val);
    }
    pushup(rt);
}
void query(int rt, int l, int r, int ql, int qr, ull &tmp1, ull &tmp2)
{
    if(ql<=l && qr>=r)
    {
        tmp1 = ( tmp1 + tree[rt].sum1*ba1[qr-r] )%mod;
        tmp2 = ( tmp2 + tree[rt].sum2*ba2[qr-r] )%mod;
    }
    else
    {
        int mid=(l + r)>>1;
        pushdown(rt);
        if(ql<=mid) query(rt<<1, l, mid, ql, qr, tmp1, tmp2);
        if(qr>mid) query(rt<<1|1, mid+1, r, ql, qr, tmp1, tmp2);
    }
}
int main()
{
    pre_did();
    while(scanf("%d%d%d", &N, &M, &Q)!=EOF)
    {
        Q+=M;
        scanf("%s", s+1);
        buildTree(1, 1, N);
        while(Q--)
        {
            int pd, l, r, d;
            scanf("%d%d%d%d", &pd, &l, &r, &d);
            if(pd==1)
            {
                update(1, 1, N, l, r, d);
            }
            else
            {
                if(r-l+1 <= d)
                {
                    printf("YES\n");
                    continue;
                }
                ull tp11=0, tp12=0;
                query(1, 1, N, l, r-d, tp11, tp12);
                ull tp21=0, tp22=0;
                query(1, 1, N, l+d, r, tp21, tp22);
                if(tp11==tp21 && tp12==tp22) printf("YES\n");
                else printf("NO\n");
            }
        }
    }
    return 0;
}

 

你觉得你会线段树吗?——做一下这道题试试吧!(来自某一研究生学长指导此处暗示的很明白了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值