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

来源:互联网 发布:写小说软件 编辑:程序博客网 时间:2024/05/29 18:34

花神的嘲讽计划Ⅰ

 昨天才看懂的可持久化线段树,被这题坑了一天。

题意:相当于给你长度为n的主串,M次查询,每次查询一个区间中长度为k的子串是否出现过。

因为长度k是确定的,我们把原来的数列所有长度为k的子序列hash然后用可持久化线段树保存起来,用大佬的话讲就是预处理出来的hash值扔进主席树里,查询即可。大致就是这样,考虑到数据范围,我把所有的hash值再进行了hash一波,这样我们只需插入权值即可,然后查询把k个数的hash值lower_bound一下,查找对应区间中的这个位置上的数是否出现过。

坑点:

hash需要用unsigned long long ,自动取余。

至今不明白为什么用fread快读不行,而普通快读可以,普通快读是2900ms左右,用scanf注意用llu输入,不能用I64u,血的教训,4500ms左右。

其余的就是可持久线段树了,还是不习惯用主席树,虽然听起来高大上,不过可持久数据结构还是主流。

const ul B=107;const ul BB=10;const int N=2e5+10;int tot,n,m,nn,k;int sum[N],root[N*40],lc[N*40],rc[N*40];ul a[N],ha[N],p[N];inline char nc(){    static char buf[100000],*p1=buf,*p2=buf;    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline int sc(){    int x=0,f=1;char ch=getchar();    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;}void init_hash(){    tot=0;    for(int i=1;i<=n;i++) ha[i]=a[i];    sort(ha+1,ha+n+1);    nn=unique(ha+1,ha+n+1)-ha-1;}int build(int l,int r){    int id=tot++;    sum[id]=0;    if(l!=r)    {        int mid=(l+r)/2;        lc[id]=build(l,mid);        rc[id]=build(mid+1,r);    }    return id;}int update(int id,int pos){   int newid=tot++,tmp=newid;   sum[newid]=sum[id]+1;   int l=1,r=nn;   while(l<r)   {       int mid=(l+r)/2;       if(pos<=mid)       {           lc[newid]=tot++;rc[newid]=rc[id];           newid=lc[newid],id=lc[id];           r=mid;       }       else       {           rc[newid]=tot++;lc[newid]=lc[id];           newid=rc[newid],id=rc[id];           l=mid+1;       }       sum[newid]=sum[id]+1;   }   return tmp;}int find(int l,int r,int pos){   int L=1,R=nn;   while(L<R)   {       int mid=(L+R)/2;       if(pos<=mid)       {           l=lc[l];           r=lc[r];           R=mid;       }       else       {          r=rc[r];          l=rc[l];          L=mid+1;       }   }   if(sum[r]-sum[l]) return 1;   return 0;}int main(){    while(~scanf("%d%d%d",&n,&m,&k))    {        p[0]=1;        ha[0]=0;        for(int i=1;i<=k;i++) p[i]=p[i-1]*B;        for(int i=1;i<=n;i++)        {            a[i]=sc();            ha[i]=ha[i-1]*B+a[i];            if(i>=k) a[i]=ha[i]-ha[i-k]*p[k];            else a[i]=ha[i];        }        init_hash();        root[0]=build(1,nn);        for(int i=1;i<=n;i++)        {            int pos=lower_bound(ha+1,ha+nn+1,a[i])-ha;            root[i]=update(root[i-1],pos);        }        while(m--)        {           int l,r;           ul x,tmp=0;           scanf("%d%d",&l,&r);           for(int i=1;i<=k;i++)           {               x=sc();               tmp=tmp*B+x;           }           int pos=lower_bound(ha+1,ha+1+nn,tmp)-ha;           if(ha[pos]==tmp&&find(root[l+k-2],root[r],pos)) puts("No");           else puts("Yes");        }    }    return 0;}

 


阅读全文
0 0
原创粉丝点击