2020 ccpc 威海 G.Caesar Cipher(线段树维护哈希)

题意:给定一个整数序列,进行q次操作,每次操作要么讲整个区间+1,要么查询某两个等长的区间是否完全相同,每次操作都要对65536取模。
思路:判断相同可以用哈希,所以用线段树维护下就行了。然后考虑怎么处理对65536取模,在线段树上再维护个最大值,每次更新后看最大值是否大于65535,然后暴力往下更新。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <set>
#include <stack>
#include <time.h>
#include <map>
#include <algorithm>
#include <fstream>
//#include <unordered_map>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 500000 + 100;
const int INF = 0x7fffffff;
const ll mod = 1e9+7;
const ll mod1 = 998244353;
const ll base = 137;
const double Pi = acos(-1.0);
const int G = 3;
int a[maxn];
int n,m;
int q[maxn];
int uu[maxn];
struct node
{
    int l,r;
    int mx;
    int has;
    int lz;
}tree[maxn*4];
void build(int i,int l,int r)
{
    tree[i].l=l;
    tree[i].r=r;
    tree[i].lz=0;
    if(l==r)
    {
        tree[i].mx=a[l];
        tree[i].has=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
    tree[i].mx=max(tree[i*2].mx,tree[i*2+1].mx);
    tree[i].has=(1ll*tree[i*2].has*q[tree[i*2+1].r-tree[i*2+1].l+1]%mod+tree[i*2+1].has)%mod;
}
void pushdown(int i)
{
    tree[i*2].mx+=tree[i].lz;
    tree[i*2].has=(1ll*tree[i*2].has+1ll*uu[tree[i*2].r-tree[i*2].l+1]*tree[i].lz%mod)%mod;
    tree[i*2+1].mx+=tree[i].lz;
    tree[i*2+1].has=(1ll*tree[i*2+1].has+1ll*uu[tree[i*2+1].r-tree[i*2+1].l+1]*tree[i].lz%mod)%mod;
    tree[i*2].lz+=tree[i].lz;
    tree[i*2+1].lz+=tree[i].lz;
    tree[i].lz=0;
}
void update(int i,int l,int r)
{
    if(tree[i].l>=l&&tree[i].r<=r)
    {
        tree[i].mx++;
        tree[i].lz++;
        tree[i].has=(1ll*tree[i].has+uu[tree[i].r-tree[i].l+1])%mod;
        return;
    }
    pushdown(i);
    if(tree[i*2].r>=l) update(i*2,l,r);
    if(tree[i*2+1].l<=r) update(i*2+1,l,r);
    tree[i].mx=max(tree[i*2].mx,tree[i*2+1].mx);
    tree[i].has=(1ll*tree[i*2].has*q[tree[i*2+1].r-tree[i*2+1].l+1]%mod+tree[i*2+1].has)%mod;
}
int query(int i,int l,int r)
{
    if(tree[i].l>=l&&tree[i].r<=r)
    {
        return tree[i].has;
    }
    pushdown(i);
    int s=0;
    if(tree[i*2].r>=l) s+=query(i*2,l,r);
    if(tree[i*2+1].l<=r) s=(1ll*s*q[max(0,min(r,tree[i*2+1].r)-tree[i*2+1].l+1)]%mod+query(i*2+1,l,r))%mod;
    return s;
}
void check(int i)
{
  //  if(tree[i].mx<65536) return;
    if(tree[i].l==tree[i].r)
    {
        tree[i].mx%=65536;
        tree[i].has=tree[i].mx;
        return;
    }
    pushdown(i);
    if(tree[i*2].mx>=65536) check(i*2);
    if(tree[i*2+1].mx>=65536) check(i*2+1);
    tree[i].mx=max(tree[i*2].mx,tree[i*2+1].mx);
    tree[i].has=(1ll*tree[i*2].has*q[tree[i*2+1].r-tree[i*2+1].l+1]%mod+tree[i*2+1].has)%mod;
}
int main()
{
    scanf("%d%d",&n,&m);
    q[0]=1;
    for(int i=1;i<=n+10;i++)
    {
        q[i]=1ll*q[i-1]*base%mod;
    }
    uu[1]=1;
    for(int i=2;i<=n+10;i++)
    {
        uu[i]=(1ll*uu[i-1]*base+1)%mod;
    }
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    build(1,1,n);
    while(m--)
    {
        int op;
        scanf("%d",&op);
        if(op==1)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            update(1,l,r);
            check(1);
        }
        else
        {
            int l,r,len;
            scanf("%d%d%d",&l,&r,&len);
            if(query(1,l,l+len-1)==query(1,r,r+len-1))
            {
                puts("yes");
            }
            else puts("no");
        }
    }
  //  system("pause");
}
上一篇:10/Jan/2021:07:21:40 to java time


下一篇:java8新日期类常用操作