bzoj3207主席树

3207: 花神的嘲讽计划Ⅰ

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 2756   Solved: 979
[ Submit][ Status][ Discuss]

Description

背景
花神是神,一大癖好就是嘲讽大J,举例如下:
“哎你傻不傻的!【hqz:大笨J】”
“这道题又被J屎过了!!”
“J这程序怎么跑这么快!J要逆袭了!”
……
描述
这一天DJ在给吾等众蒟蒻讲题,花神在一边做题无聊,就跑到了一边跟吾等众蒟蒻一起听。以下是部分摘录:
1.
“J你在讲什么!”
“我在讲XXX!”
“哎你傻不傻的!这么麻烦,直接XXX再XXX就好了!”
“……”
2.
“J你XXX讲过了没?”
“……”
“那个都不讲你就讲这个了?哎你傻不傻的!”
“……”
DJ对这种情景表示非常无语,每每出现这种情况,DJ都是非常尴尬的。
经过众蒟蒻研究,DJ在讲课之前会有一个长度为N方案,我们可以把它看作一个数列;
同样,花神在听课之前也会有一个嘲讽方案,有M个,每次会在x到y的这段时间开始嘲讽,为了减少题目难度,每次嘲讽方案的长度是一定的,为K。
花神嘲讽DJ让DJ尴尬需要的条件:
在x~y的时间内DJ没有讲到花神的嘲讽方案,即J的讲课方案中的x~y没有花神的嘲讽方案【这样花神会嘲讽J不会所以不讲】。
经过众蒟蒻努力,在一次讲课之前得到了花神嘲讽的各次方案,DJ得知了这个消息以后欣喜不已,DJ想知道花神的每次嘲讽是否会让DJ尴尬【说不出话来】。

Input

第1行3个数N,M,K;
第2行N个数,意义如上;
第3行到第3+M-1行,每行K+2个数,前两个数为x,y,然后K个数,意义如上;

Output

对于每一个嘲讽做出一个回答会尴尬输出‘Yes’,否则输出‘No’

Sample Input

8 5 3
1 2 3 4 5 6 7 8
2 5 2 3 4
1 8 3 2 1
5 7 4 5 6
2 5 1 2 3
1 7 3 4 5

Sample Output

No
Yes
Yes
Yes
No

HINT

题中所有数据不超过2*10^9;保证方案序列的每个数字<=N

2~5中有2 3 4的方案,输出No,表示DJ不会尴尬

1~8中没有3 2 1的方案,输出Yes,表示DJ会尴尬

5~7中没有4 5 6的方案,输出Yes,表示DJ会尴尬

2~5中没有1 2 3的方案,输出Yes,表示DJ会尴尬

1~7中有3 4 5的方案,输出No,表示DJ不会尴尬

题目描述很强

题意:区间定长字符串是否出现。

首先显然字符串哈希一下(我是暴力水过去的)

然后如果该字符串从未出现过,直接pass

然后勒,就是主席树的套路了。是否出现过,就维护到从头到当前字符每个字符串出现次数。询问时两个区间减一下就可以求出现次数了。如果两个区间在某些个包含询问字符串的字符串集合中已经一模一样(及t[l] – t[r] == 0)就说明这个区间没有这个字符串了,直接pass即可。

贴个码

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
#define maxn 100005
using namespace std;
int read()
{
	char ch = getchar(); int x = 0, f = 1;
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
	return x * f;
}

struct Tree {
	int l, r, sum;
}t[maxn * 20];
int N, n, m, k, top, a[maxn], pos[maxn], hash[maxn], root[maxn], val[maxn];

bool cmp(int x, int y)
{
	for(int i = 0;i < k; ++i)
	{
		if(a[x + i] < a[y + i]) return true;
		if(a[x + i] > a[y + i]) return false;
	}
	return false;
}

bool judge(int x, int y)
{
	for(int i = 0;i < k; ++i)
		if(a[x + i] != a[y + i]) return true;
	return false;
}

void Insert(int &cur_p, int pre_p, int position, int L, int R)
{
	t[cur_p = ++top] = t[pre_p];
	++t[cur_p].sum;
	if(L == R) return;
	int mid = L + R >> 1;
	if(position <= mid) Insert(t[cur_p].l, t[pre_p].l, position, L, mid);
	else Insert(t[cur_p].r, t[pre_p].r, position, mid + 1, R);
}

bool query(int lt, int rt, int position, int L, int R)
{
	if(!(t[rt].sum - t[lt].sum)) return false;
	if(L == R) return true;
	int mid = L + R >> 1;
	if(position <= mid) return query(t[lt].l, t[rt].l, position, L, mid);
	else return query(t[lt].r, t[rt].r, position, mid + 1, R);
}

void get_hash()
{
	sort(pos + 1, pos + N + 1, cmp); n = 0;
	hash[pos[1]] = ++n;
	for(int i = 2;i <= N; ++i)
	{
		if(judge(pos[i - 1], pos[i])) hash[pos[i]] = ++n;
		else hash[pos[i]] = n;
	}
}

void init()
{
	
	N = read(); m = read(); k = read();
	for(int i = 1;i <= N; ++i) {
		a[i] = read();
		pos[i] = i;
	}
	get_hash();
	root[0] = 0;
	for(int i = 1;i <= n - k + 1; ++i) 
		Insert(root[i], root[i - 1], hash[i], 1, n);
}

int compare(int x)
{
	for(int i = 0;i < k; ++i)
	{
		if(a[x + i] > val[i]) return 1;
		if(a[x + i] < val[i]) return -1;
	}
	return 0;
}

int dicho()
{
	for(int i = 0;i < k; ++i) val[i] = read();
	int l = 0, r = n;
	while(l <= r)
	{
		int mid = l + r >> 1; int p = compare(pos[mid]);
		if(p > 0) r = mid - 1;
		else if(p < 0) l = mid + 1;
		else return mid;
	}
	return -1;
}

void solve()
{
	for(int i = 1;i <= m; ++i)
	{
		int l = read(), r = read();
		int p = dicho();
		if(!(~p)) puts("Yes");
		else if(query(root[l - 1], root[r - k + 1], hash[pos[p]], 1, n)) puts("No");
		else puts("Yes");
	}
}

int main()
{
	init();
	solve();
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值