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; }