BZOJ3207: 花神的嘲讽计划Ⅰ
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3207
可持久化线段树。
把每段数字都hash起来,然后把询问的数字段也hash起来。
然后询问的时候做减法就可以了。
#include<cstring> #include<iostream> #include<algorithm> #include<cstdio> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 200500 #define seed 419LL #define mm 1000000007 #define ll unsigned long long using namespace std; struct data{ll x;int id,l,r; }a[maxn],q[maxn*3]; int sum[maxn*40],ls[maxn*40],rs[maxn*40],root[maxn*3],num[maxn]; ll c[maxn]; int ss,cnt,n,m,k,cnt2; 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; } ll get(int x){ ll ans=0; rep(i,x,x+k-1) ans=ans*seed+c[i]; return ans; } bool cmp(data a,data b){ return a.x<b.x; } void add(int l,int r,int x,int &y,int val){ y=++cnt2; sum[y]=sum[x]+1; if (l==r) return; ls[y]=ls[x]; rs[y]=rs[x]; int mid=(l+r)/2; if (val<=mid) add(l,mid,ls[x],ls[y],val); else add(mid+1,r,rs[x],rs[y],val); } int ask(int l,int r,int t,int val){ if (l==r) return sum[t]; int mid=(l+r)/2; if (val<=mid) return ask(l,mid,ls[t],val); else return ask(mid+1,r,rs[t],val); } int main(){ n=read(); m=read(); k=read(); rep(i,1,n) scanf("%lld",&c[i]); rep(i,1,n-k+1) a[i].id=i,a[i].x=get(i); cnt=n-k+1; rep(i,1,m){ q[i].l=read()-1; q[i].r=read()-k+1; rep(j,1,k) scanf("%lld",&c[j]); cnt++; a[cnt].id=cnt; a[cnt].x=get(1); } sort(a+1,a+1+cnt,cmp); ss=1; num[a[1].id]=1; rep(i,2,cnt){ if (a[i].x!=a[i-1].x) ss++; num[a[i].id]=ss; } rep(i,1,n-k+1) add(1,ss,root[i-1],root[i],num[i]); rep(i,1,m){ if (ask(1,ss,root[q[i].r],num[i+n-k+1])-ask(1,ss,root[q[i].l],num[i+n-k+1])>0) puts("No"); else puts("Yes"); } return 0; }