BZOJ-3207 花神的嘲讽计划Ⅰ
貌似是先把各个子串处理成各个Hash值,然后离散化,然后这道题就变成询问区间[x,y]中有没有数字k。
主席树直接上。。。
#include <cstdlib> #include <cstdio> #include <cctype> #include <cstring> #include <cmath> #include <iostream> #include <algorithm> #define rep(i, l, r) for(int i=l; i<=r; i++) #define clr(x, c) memset(x, c, sizeof(x)) #define lowbit(x) (x&-x) #define maxn 600009 #define maxm 5000009 #define hash 2333 #define inf 0x7fffffff #define s(x) Sum[x] #define t(x) Tree[x] #define l(x) Left[x] #define r(x) Right[x] #define k(x) Key[x] #define ull unsigned long long using namespace std; inline int read() { int x=0, f=1; char ch=getchar(); while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)) x=x*10+ch-'0', ch=getchar(); return x*f; } struct node{ull v; int t;} q[maxn]; bool cmp(node a, node b){return a.v<b.v;} int n, m, k, z, ln, qx[maxn], qy[maxn], a[maxn]; int Tree[maxn], Left[maxm], Right[maxm], Sum[maxm], Key[maxm]; inline ull Hash(int x){ull now=1; rep(i, 0, k-1) now=now*hash+a[i+x]; return now;} void Add(int k, int l, int r, int u, int &t) { if (!t) t=++z; s(t)=s(u)+1; if (l==r) return; int mid=(l+r)>>1; if (k<=mid) r(t)=r(u), Add(k, l, mid, l(u), l(t)); else l(t)=l(u), Add(k, mid+1, r, r(u), r(t)); } inline bool Query(int l, int r, int k) { int L=1, R=ln, x=t(l-1), y=t(r); while (L<R) { if (s(y)-s(x)==0) return false; int mid=(L+R)>>1; if (k<=mid) R=mid, x=l(x), y=l(y); else L=mid+1, x=r(x), y=r(y); } if (s(y)-s(x)) return true; else return false; } int main() { n=read(), m=read(), k=read(); t(0)=++z, l(z)=r(z)=z; rep(i, 1, n) a[i]=read(); rep(i, 1, n-k+1) q[i].v=Hash(i), q[i].t=i; n=n-k+1; rep(i, 1, m) { qx[i]=read(), qy[i]=read()-k+1; rep(j, 1, k) a[j]=read(); q[i+n].v=Hash(1), q[i+n].t=i+n; } sort(q+1, q+m+n+1, cmp); k(q[1].t)=++ln; rep(i, 2, n+m) k(q[i].t) = q[i].v!=q[i-1].v ? ++ln : ln; rep(i, 1, n) Add(k(i), 1, ln, t(i-1), t(i)); rep(i, 1, m) if (Query(qx[i], qy[i], k(i+n))) printf("No\n"); else printf("Yes\n"); return 0; }