BZOJ 3207 花神的嘲讽计划Ⅰ主席树+Hash

题意:
当前有一个序列。
多次询问某一个子序列中是否存在某一个长度为k的序列(连续)。
非强制在线。
解析:
由于本题非强制在线所以可能有各种奇怪的方法叉过去。
但是咱们要把它看成强制在线的来做嘛!
由于题中这个K的限制非常好。
所以我们可以预处理出所有的点到其+k-1的子区间的hash值。
然后扔到权值线段树中。
但是这里有个问题就是我们一个线段树的话版本不够?
我们需要查询某一段区间中是否存在一个询问的Hash。
所以这里可以考虑上一个主席树。
即可解决。
代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 100100
#define base 131
#define INF 18446744073709551615ull
using namespace std;
typedef unsigned long long ull;
int n,m,k;
int size;
int a[N];
int root[N]; 
struct node
{
    int lson,rson,sum;
}seg[N*70];
void insert(int x,int &y,ull l,ull r,ull v)
{
    y=++size;
    seg[y]=seg[x];
    seg[y].sum++; 
    if(l==r)return;
    ull mid=(l>>1)+(r>>1)+(l&r&1);
    if(v<=mid)insert(seg[x].lson,seg[y].lson,l,mid,v);
    else insert(seg[x].rson,seg[y].rson,mid+1,r,v);
}
int query(int x,int y,ull l,ull r,ull v)
{
    if(seg[y].sum-seg[x].sum==0)return 0;
    if(l==r)return 1;
    ull mid=(l>>1)+(r>>1)+(l&r&1);
    if(v<=mid)return query(seg[x].lson,seg[y].lson,l,mid,v);
    else return query(seg[x].rson,seg[y].rson,mid+1,r,v);
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        ull hash=0;
        for(int j=i;j<=i+k-1;j++)
        {
            hash=hash*base+a[j];
        }
        insert(root[i-1],root[i],0,INF,hash);
    }
    for(int i=1;i<=m;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        ull hash=0;
        for(int j=1;j<=k;j++)
        {
            int v;
            scanf("%d",&v);
            hash=hash*base+v;
        }
        if(query(root[l-1],root[r-k+1],0,INF,hash))puts("No");
        else puts("Yes"); 
    }
}

你可能感兴趣的:(hash,C语言,X,bzoj)