gym102798 Caesar Cipher (2020 China Collegiate Programming Contest, Weihai Site) 线段树

题意

有一个一个长度为n的数组a和两种操作(1代表对区间([l,r])加1,2代表询问区间([x,x+L-1])和区间([y,y+L-1])是否相同),其中操作1对65536取模。

思路

容易想到可以用哈希判断是否相等。然后题目中的数组是对65536取模的,就会想到hash的模数取65536,即用unsigned short自然溢出取模,但是这个模数被出题人卡掉了。

另外,做字符串哈希时,哈希的模数一般会选用大指数。因为当base和mod互质时,这个hash函数在([0,mod))上每个值概率相等,此时单次比较的错误率为(frac1{mod})

对于65536取模的情况,与codeforces438D相同,除了区间和外再加一个区间最大值,对于大于等于65536的区间暴力修改。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const ll base=1e8+7;
const int maxn=5e5+5;

struct Tree{
    ll max,sum,tag;
}tree[maxn*4];
ll a[maxn],p[maxn],pre[maxn];
int n,q;


ll M(ll val){
    return val>=mod?val-mod:val<0?val+mod:val;
}

void push_up(int i)
{
    tree[i].max=max(tree[i<<1].max,tree[i<<1|1].max);
    tree[i].sum=M(tree[i<<1].sum+tree[i<<1|1].sum);
}

void push_down(int i,int L,int R)
{
    if(tree[i].tag)
    {
        tree[i<<1].max+=tree[i].tag;
        tree[i<<1|1].max+=tree[i].tag;
        int mid=L+R>>1;
        if(L!=mid)
            tree[i<<1].tag+=tree[i].tag;
        if(mid+1!=R)
            tree[i<<1|1].tag+=tree[i].tag;
        tree[i<<1].sum=M(tree[i<<1].sum+M(pre[mid]-pre[L-1])*tree[i].tag%mod);
        tree[i<<1|1].sum=M(tree[i<<1|1].sum+M(pre[R]-pre[mid])*tree[i].tag%mod);
        tree[i].tag=0;
    }
}

void build(int i,int l,int r)
{
    if(l==r)
    {
        tree[i].max=a[l];
        tree[i].sum=a[l]*p[l]%mod;
        tree[i].tag=0;
        return;
    }
    int mid=l+r>>1;
    build(i<<1,l,mid);
    build(i<<1|1,mid+1,r);
    push_up(i);
}

void add(int i,int l,int r,int L,int R)
{
    push_down(i,L,R);
    if(l==L && r==R)
    {
        if(l==r)
        {
            tree[i].max++;
            if(tree[i].max==65536)tree[i].max=0;
            tree[i].sum=tree[i].max*p[l]%mod;
            return;
        }
        else if(tree[i].max<65535)
        {            
            tree[i].max++;
            tree[i].tag++;
            tree[i].sum=M(tree[i].sum+M(pre[R]-pre[L-1]));
            return;
        }
    }
    int mid=L+R>>1;
    if(r<=mid)
        add(i<<1,l,r,L,mid);
    else if(l>mid)
        add(i<<1|1,l,r,mid+1,R);
    else
    {
        add(i<<1,l,mid,L,mid);
        add(i<<1|1,mid+1,r,mid+1,R);
    }
    push_up(i);
}

ll cal(int i,int l,int r,int L,int R)
{
    push_down(i,L,R);
    int mid=L+R>>1;
    if(l==L && r==R)return tree[i].sum;
    if(r<=mid)
        return cal(i<<1,l,r,L,mid);
    else if(l>mid)
        return cal(i<<1|1,l,r,mid+1,R);
    else
        return M(cal(i<<1,l,mid,L,mid)+cal(i<<1|1,mid+1,r,mid+1,R));
}

int main()
{
    ios::sync_with_stdio(false);

    cin>>n>>q;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    p[0]=1;
    pre[0]=1;
    for(int i=1;i<=n;i++)
    {
        p[i]=p[i-1]*base%mod;
        pre[i]=M(pre[i-1]+p[i]);
    }

    build(1,1,n);
    int op,l,r,x,y,L;
    while(q--)
    {
        cin>>op;
        if(op==1)
        {
            cin>>l>>r;
            add(1,l,r,1,n);
        }
        else
        {
            cin>>x>>y>>L;
            if(x>y)swap(x,y);
            ll res1=cal(1,x,x+L-1,1,n),res2=cal(1,y,y+L-1,1,n);
            if(res1*p[y-x]%mod==res2)
                cout<<"yes
";
            else
                cout<<"no
";
        }
        
    }

    return 0;
}
原文地址:https://www.cnblogs.com/intmian/p/14015085.html