bzoj 3207 可持久化线段树

  首先因为固定询问长度,所以我们可以将整个长度为n的数列hash成长度为n-k+1的数列,每次询问的序列也hash成一个数,然后询问这个数是不是在某个区间中出现过,这样我们可以根据初始数列的权值建立可持久化线段树,对于每个询问先二分判断是否出现在数列中过,然后再判断是否在区间内出现过。也可以离线将询问和数列建立可持久化线段树,那么直接判断就可以了,但是空间消耗会大些。

  反思:偷懒直接用的map判的是否出现,然后改了hash用long long存之后map_insert没有改,然后就一直WA。

     不知道数据的范围,开大了数组好多。

/**************************************************************
    Problem: 3207
    User: BLADEVIL
    Language: C++
    Result: Accepted
    Time:6580 ms
    Memory:130804 kb
****************************************************************/
 
//By BLADEVIL
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 500010
#define LL long long
  
using namespace std;
   
struct segment {
    int left,right,cnt;
    int son[2];
    segment() {
        left=right=cnt=0;
        memset(son,0,sizeof son);
    }
}t[12*maxn];
   
struct rec {
    int num,key;
    LL hash;
    rec() {
        hash=num=key=0;
    }
}a[maxn];
   
int n,m,k,sum,tot;
int rot[maxn];
map<LL,int>tree;
   
bool cmp1(rec x,rec y) {
    return x.hash<y.hash;
}
   
bool cmp2(rec x,rec y) {
    return x.num<y.num;
}
   
void map_insert(LL x,int y) {
    if (tree.find(x)==tree.end()) tree.insert(pair<LL,int>(x,y));
}
   
void build(int &x,int l,int r) {
    if (!x) x=++tot;
    t[x].left=l; t[x].right=r;
    if (l==r) return ;
    int mid=t[x].left+t[x].right>>1;
    build(t[x].son[0],l,mid); build(t[x].son[1],mid+1,r);
}
   
void insert(int &x,int rot,int y) {
    if (!x) x=++tot;
    t[x].left=t[rot].left; t[x].right=t[rot].right;
    if (t[x].left==t[x].right) {
        t[x].cnt=t[rot].cnt+1;
        return ;
    }
    int mid=t[x].left+t[x].right>>1;
    if (y>mid) {
        t[x].son[0]=t[rot].son[0];
        insert(t[x].son[1],t[rot].son[1],y);
    } else {
        t[x].son[1]=t[rot].son[1];
        insert(t[x].son[0],t[rot].son[0],y);
    }
    t[x].cnt=t[rot].cnt+1;
}
   
int query(int lx,int rx,int y) {
    if (t[lx].left==t[lx].right) return t[rx].cnt-t[lx].cnt;
    int mid=t[lx].left+t[lx].right>>1;
    if (y>mid) return query(t[lx].son[1],t[rx].son[1],y); else return query(t[lx].son[0],t[rx].son[0],y);
}
   
int main() {
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=n;i++) scanf("%d",&a[i].key);
    n=n-k+1;
    for (int i=1;i<=n;i++) 
        for (int j=i;j<=i+k-1;j++) a[i].hash=a[i].hash*107+a[j].key;
    for (int i=1;i<=n;i++) a[i].num=i;
    sort(a+1,a+n+1,cmp1); sum=1; LL cur=a[1].hash;
    //for (int i=1;i<=n;i++) printf("%d ",a[i].hash); printf("\n");
    for (int i=1;i<=n;i++)
        if (a[i].hash==cur) a[i].key=sum; else cur=a[i].hash,a[i].key=++sum;
    sort(a+1,a+n+1,cmp2);
    //for (int i=1;i<=n;i++) printf("%d ",a[i].key); printf("\n"); 
    for (int i=1;i<=n;i++) map_insert(a[i].hash,a[i].key);
    build(rot[0],1,sum);
    for (int i=1;i<=n;i++) insert(rot[i],rot[i-1],a[i].key);
    while (m--) {
        int l,r; scanf("%d%d",&l,&r); if (r>n) r=n;
        LL ha=0;
        for (int i=1;i<=k;i++) {
            int x; scanf("%d",&x);
            ha=ha*107+x;
        }
        map<LL,int>::iterator p=tree.find(ha);
        if (p==tree.end()) {
            printf("Yes\n");
            continue;
        }
        int y=p->second;
        if (query(rot[l-1],rot[r],y)>0) printf("No\n"); else printf("Yes\n");
        //printf("%d\n",query(rot[l-1],rot[r],y));
    }
    return 0;
}

 

posted on 2014-04-18 07:39  BLADEVIL  阅读(741)  评论(0编辑  收藏  举报