BZOJ 3207: 花神的嘲讽计划Ⅰ

本文通过解决一个具体的字符串匹配问题,介绍了如何使用主席树和莫队算法进行高效查询。文章首先描述了作者因误解题意而采取的绕弯路过程,随后详细解释了正确的解决方案:利用哈希值存储字符串并借助主席树判断目标子串是否存在。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刷点水题舒缓心情

一开始没读懂题以为是查询那些数是不是都在那个区间里

于是开始写主席树,写完发现不对QAQ

题目是求那个区间里是否存在一个字串和给定串相等

由于串长是一定的,每个节点存以该节点为结尾的长度为K的字符串的哈希值

然后用主席树判断是否存在即可

(读错题后一怒之下把主席树删了写了个特技莫队,跑得还挺快的)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
#include<map>
#include<set>
#include<stack>
#include<cstdlib>
#include<ctime>
#define rep(i,l,r) for(int i=l;i<=r;i++)
#define per(i,r,l) for(int i=r;i>=l;i--)
#define mmt(a,v) memset(a,v,sizeof(a))
#define tra(i,u) for(int i=head[u];i;i=e[i].next)
using namespace std;
typedef unsigned long long ull;
const int N=100000+5;
const int p=107;
int b[N];
struct Node{
	int l,r,id;
	ull v;
	bool operator < (const Node &x)const{
		return b[l]==b[x.l]?((r<x.r)^(b[l]&1)):b[l]<b[x.l];
	}
}q[N];
int a[N],n,m,k,tot,cnt[N];
ull h[N],s[N];
bool ans[N];
bool find(ull x){
	int t=lower_bound(h+k,h+1+n,x)-h;
	if(t>n||h[t]!=x)return false;
	return cnt[t]?1:0;
}
int main(){
	//freopen("a.in","r",stdin);
	scanf("%d%d%d",&n,&m,&k);
	rep(i,1,n)scanf("%d",&a[i]),s[i]=s[i-1]*p+a[i];
	ull t=1;rep(i,1,k)t*=p;
	rep(i,k,n)h[i]=s[i]-s[i-k]*t;
	sort(h+k,h+n+1);
	rep(i,k,n)a[i]=lower_bound(h+k,h+1+n,s[i]-s[i-k]*t)-h;
	int S=sqrt(m+0.5);
	rep(i,1,n)b[i]=(i-1)/S;
	rep(i,1,m){
		scanf("%d%d",&q[i].l,&q[i].r);q[i].id=i;
		q[i].l+=k-1;
		ull ans=0;
		int x;
		rep(j,1,k){scanf("%d",&x);ans=ans*p+x;}
		q[i].v=ans;
	}
	sort(q+1,q+1+m);
	int ql=1,qr=0;
	rep(i,1,m){
		while(qr<q[i].r)cnt[a[++qr]]++;
		while(ql>q[i].l)cnt[a[--ql]]++;
		while(qr>q[i].r)cnt[a[qr--]]--;
		while(ql<q[i].l)cnt[a[ql++]]--;
		ans[q[i].id]=find(q[i].v);
	}
	rep(i,1,m)puts(ans[i]?"No":"Yes");
	return 0;
}
		


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值