您的位置:首页 > 其它

bzoj 3207: 花神的嘲讽计划Ⅰ (主席树+hash)

2017-03-28 10:16 465 查看

题目描述

传送门

题解

对于每个位置的权值为[i,i+k-1]这一段的hash值。

离散化之后依次插入主席树中。

查询的时候先找到这一段离散后的值,然后查询[x,y-k+1]这一段中是否出现过。

代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<map>
#define ull unsigned long long
#define p 2000001001
#define N 100003
using namespace std;
struct data{
int l,r,sum;
}tr[N*20];
map<ull,int> mp;
int sz,root
,a
,n,m,k,cnt;
ull mi
,val
,b
;
void insert(int &i,int j,int l,int r,int x)
{
i=++sz; tr[i]=tr[j];
tr[i].sum++;
if (l==r) return;
int mid=(l+r)/2;
if (x<=mid) insert(tr[i].l,tr[j].l,l,mid,x);
else insert(tr[i].r,tr[j].r,mid+1,r,x);
}
int qjsum(int i,int j,int l,int r,int x)
{
if (l==r) return tr[j].sum-tr[i].sum;
int mid=(l+r)/2;
if (x<=mid) return qjsum(tr[i].l,tr[j].l,l,mid,x);
else return qjsum(tr[i].r,tr[j].r,mid+1,r,x);
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d%d%d",&n,&m,&k);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
mi[0]=1;
for (int i=1;i<=k;i++) mi[i]=mi[i-1]*p;
for (int i=1;i<=n-k+1;i++) {
val[i]=0;
for (int j=1;j<=k;j++)
val[i]+=mi[j]*(ull)a[i+j-1];
///cout<<val[i]<<endl;
b[i]=val[i];
}
sort(b+1,b+n+1);
cnt=unique(b+1,b+n+1)-b-1;
for (int i=1;i<=n-k+1;i++) {
a[i]=lower_bound(b+1,b+cnt+1,val[i])-b;
mp[val[i]]=a[i];
}
//for (int i=1;i<=n-k+1;i++) cout<<a[i]<<" "; cout<<endl;
for (int i=1;i<=n-k+1;i++) insert(root[i],root[i-1],1,n,a[i]);
for (int i=1;i<=m;i++) {
int x,y; scanf("%d%d",&x,&y);
ull t=0;
for (int j=1;j<=k;j++) {
int c; scanf("%d",&c);
t+=(ull)mi[j]*(ull)c;
}
//cout<<t<<endl;
if (!mp[t]||y-x+1<k) {
printf("Yes\n");
continue;
}
//cout<<mp[t]<<endl;
if (qjsum(root[x-1],root[y-k+1],1,n,mp[t])) printf("No\n");
else printf("Yes\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  主席树 hash