现在的位置: 首页 > 综合 > 正文

BZOJ 3207 花神的嘲讽计划Ⅰ Hash+可持久化线段树

2018年01月19日 ⁄ 综合 ⁄ 共 1897字 ⁄ 字号 评论关闭

题目大意:给出一个序列,问一个区间里有没有长度为定长的已知序列。

思路:第一步的想法是把序列哈希一下,如果暴力的话,就是在区间里面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;
}

抱歉!评论已关闭.