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

来源:互联网 发布:现代文翻译古文软件 编辑:程序博客网 时间:2024/05/29 21:35

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

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define N 100100#define base 131#define INF 18446744073709551615ullusing 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");     }}
1 0
原创粉丝点击