cf213E 线段树维护hash

Posted dsrdsr

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cf213E 线段树维护hash相关的知识,希望对你有一定的参考价值。

链接

https://codeforces.com/contest/213/problem/E

题目大意

给出两个排列a、b,长度分别为n、m,你需要计算有多少个x,使
(a_1 + x; a_2 + x; a_3 + x、、、 a_n + x) 是b 的子序列(不连续的那种)。

思路

巧妙啊
暴力直接扫会T
我们构造一个c数组,使得c[b[i]]=i
这样x+1到x+1+n就是一段连续的区间了233
插回去看看他们相对大小是不是和a数组相同
因为不连续所以线段树维护hash值,线段树按照c数组的原路插回去
查询这一段是否hash值相同
????乛?乛????
不知道双进制有没有用

错误

报错:你数组开小啦
我:我靠,ull炸了,改改改

代码

#include <iostream>
#include <cstdio>
#define ull unsigned long long
using namespace std;
const int N=2e5+7;
const int mod[2]={233,1000000009};
int read() {
    int x=0,f=1;char s=getchar();
    for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    return x*f;
}
int n,m,pos[N],a[N],b[N];
ull my_pow[2][N];
namespace seg {
    #define ls rt<<1
    #define rs rt<<1|1
    struct node {
        int siz;
        ull tot[2];
    }e[N<<2];
    int cnt;
    void pushup(int rt) {
        e[rt].siz=e[ls].siz+e[rs].siz;
        e[rt].tot[0]=(e[ls].tot[0]*my_pow[0][e[rs].siz+1]+e[rs].tot[0]);
        e[rt].tot[1]=(e[ls].tot[1]*my_pow[1][e[rs].siz+1]+e[rs].tot[1]);
    }
    void update(int l,int r,int id,int k,int rt) {
        if(l==r) {
            if(k==-1) e[rt].siz=e[rt].tot[0]=e[rt].tot[1]=0;
            else e[rt].siz=1,e[rt].tot[0]=e[rt].tot[1]=k;
            return;
        }
        int mid=(l+r)>>1;
        if(id<=mid) update(l,mid,id,k,ls);
        else update(mid+1,r,id,k,rs);
        pushup(rt);
    }
}
int main() {
    n=read(),m=read();
    my_pow[1][1]=my_pow[0][1]=1;
    for(int i=2;i<=n+1;++i) {
        my_pow[0][i]=my_pow[0][i-1]*mod[0];
        my_pow[1][i]=my_pow[1][i-1]*mod[1];
    }
    for(int i=1;i<=n;++i) a[i]=read();
    for(int i=1;i<=m;++i) b[i]=read();
    ull hash[2]={0,0},tmp[2]={0,0};
    for(int i=1;i<=n;++i) {
        hash[0]=(hash[0]*mod[0]+a[i]);
        hash[1]=(hash[1]*mod[1]+a[i]);
        tmp[0]=(tmp[0]*mod[0]+1);
        tmp[1]=(tmp[1]*mod[1]+1);
    }
    for(int i=1;i<=m;++i) pos[b[i]]=i;
    int ans=0;
    for(int i=1;i<=m;++i) {
        if(i>n) seg::update(1,m,pos[i-n],-1,1);
        seg::update(1,m,pos[i],i,1);
        if(i>=n&&seg::e[1].tot[0]==(tmp[0]*(i-n)+hash[0])&&
                 seg::e[1].tot[1]==(tmp[1]*(i-n)+hash[1])) ans++;
    }
    cout<<ans<<"
";
    return 0;
}

以上是关于cf213E 线段树维护hash的主要内容,如果未能解决你的问题,请参考以下文章

线段树维护区间合并——cf1285E

codeforces CF718C Sasha and Array 线段树维护矩阵

CF718C Sasha and Array(线段树维护矩阵)

CF - 1108 E 枚举上界+线段树维护

CF1009F Dominant Indices [线段树合并]

CF 633G 线段树+bitset