题目大意:给出一个序列,问一个区间里有没有长度为定长的已知序列。
思路:第一步的想法是把序列哈希一下,如果暴力的话,就是在区间里面O(n)的去判断,但是这样显然太慢了,我们需要O(logn)的时间之内求出区间内有没有一个值。这个问题就可以用可持久化线段树或者划分树来解决了。划分树我不咋会,就写了可持久化线段树。代码略丑,见谅。
CODE:
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 200010 #define MAX_POOL (MAX * 50) #define MAX_ULL 18446744073709551615ull using namespace std; const int key = 999911659; const int _key = 999911657; struct SegTree{ int cnt; SegTree *son[2]; }*tree[MAX],mempool[MAX_POOL],*C = mempool; int cnt,asks,length; int src[MAX]; unsigned long long _hash[MAX],hash[MAX]; unsigned long long power[MAX]; void Pretreatment() { power[0] = 1; for(int i = 1; i <= length; ++i) power[i] = power[i - 1] * key; } inline SegTree *NewNode(int _,SegTree *__,SegTree *___) { C->cnt = _; C->son[0] = __; C->son[1] = ___; return C++; } SegTree *BuildTree(SegTree *consult,unsigned long long l,unsigned long long r,unsigned long long x) { if(l == r) return NewNode(consult->cnt + 1,NULL,NULL); unsigned long long mid = (l >> 1) + (r >> 1) + (l&r&1); if(x <= mid) return NewNode(consult->cnt + 1,BuildTree(consult->son[0],l,mid,x),consult->son[1]); else return NewNode(consult->cnt + 1,consult->son[0],BuildTree(consult->son[1],mid + 1,r,x)); } bool Ask(SegTree *end,SegTree *start,unsigned long long l,unsigned long long r,unsigned long long x) { if(!(end->cnt - start->cnt)) return false; if(l == r) return true; unsigned long long mid = (l >> 1) + (r >> 1) + (l&r&1); if(x <= mid) return Ask(end->son[0],start->son[0],l,mid,x); return Ask(end->son[1],start->son[1],mid + 1,r,x); } int main() { cin >> cnt >> asks >> length; Pretreatment(); for(int i = 1; i <= cnt; ++i) { scanf("%d",&src[i]); _hash[i] = _hash[i - 1] * key + src[i]; } tree[length - 1] = NewNode(0,C,C); for(int i = length; i <= cnt; ++i) { hash[i] = _hash[i] - _hash[i - length] * power[length]; tree[i] = BuildTree(tree[i - 1],0,MAX_ULL,hash[i]); } for(int x,y,i = 1; i <= asks; ++i) { scanf("%d%d",&x,&y); unsigned long long hash = 0; for(int z,j = 1; j <= length; ++j) { scanf("%d",&z); hash = hash * key + z; } x = x + length - 1; if(x > y) printf("Yes\n"); else printf("%s\n",Ask(tree[y],tree[x - 1],0,MAX_ULL,hash) ? "No":"Yes"); } return 0; }
BZOJ 3207 花神的嘲讽计划Ⅰ Hash+可持久化线段树
原文地址:http://blog.csdn.net/jiangyuze831/article/details/40785901