题意:
当前有一个序列。
多次询问某一个子序列中是否存在某一个长度为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");
}
}