码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2014-11-04 17:34:01      阅读:120      评论:0      收藏:0      [点我收藏+]

标签:bzoj   花神   可持久化线段树   hash   

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


思路:第一步的想法是把序列哈希一下,如果暴力的话,就是在区间里面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+可持久化线段树

标签:bzoj   花神   可持久化线段树   hash   

原文地址:http://blog.csdn.net/jiangyuze831/article/details/40785901

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!