主席树+哈希套路。通过哈希做到快速比较一些东西是否相等,很可能和字典序什么的有关。
这题就是利用哈希,在主席树上二分一样地走,找到从左边开始第一个不一样的和从右边开始第一个不一样的,然后xjb判断一下就好了。
#include<cstdio>
#include<algorithm>
#define Lh ch[0]->hsh
#define Rh ch[1]->hsh
#define Ls ch[0]->sum
#define Rs ch[1]->sum
using namespace std;
typedef unsigned long long uLL;
const uLL maxn=100015,con=23333,maxv=100000;
uLL pw[maxn];
struct node{
node* ch[2];
node(node* son=NULL){ ch[0]=ch[1]=son; hsh=sum=0; }
void maintain(int lenR){
hsh=ch[0]->hsh*pw[lenR]+ch[1]->hsh;
sum=ch[0]->sum+ch[1]->sum;
}
uLL hsh; int sum;
} base[10000005], nil, *null=&nil, *p_top=base;
typedef node* P_node;
P_node newnode(){ p_top->hsh=p_top->sum=0; p_top->ch[0]=p_top->ch[1]=null; return p_top++; }
P_node build(int L,int R){
P_node p=newnode();
if(L==R) return p;
int mid=(L+R)>>1;
p->ch[0]=build(L,mid); p->ch[1]=build(mid+1,R);
return p;
}
P_node Updata(P_node pre,int L,int R,int pos){
P_node p=newnode();
if(L==R){ p->hsh=pre->hsh+1; p->sum=pre->sum+1; return p; }
int mid=(L+R)>>1;
p->ch[0]=pre->ch[0]; p->ch[1]=pre->ch[1];
if(pos<=mid) p->ch[0]=Updata(pre->ch[0],L,mid,pos);
else p->ch[1]=Updata(pre->ch[1],mid+1,R,pos);
p->maintain(R-mid); return p;
}
int QueryL(P_node p1,P_node p2,P_node p3,P_node p4,int L,int R){ //(p1,p2], (p3,p4]
if(L==R) return min(p2->sum-p1->sum,p4->sum-p3->sum);
if(p2->hsh-p1->hsh==p4->hsh-p3->hsh) return p2->sum-p1->sum;
int mid=(L+R)>>1;
if(p2->Lh-p1->Lh!=p4->Lh-p3->Lh) return QueryL(p1->ch[0],p2->ch[0],p3->ch[0],p4->ch[0],L,mid);
else return (p2->Ls-p1->Ls)+QueryL(p1->ch[1],p2->ch[1],p3->ch[1],p4->ch[1],mid+1,R);
}
int QueryR(P_node p1,P_node p2,P_node p3,P_node p4,int L,int R){ //(p1,p2], (p3,p4]
if(L==R) return min(p2->sum-p1->sum,p4->sum-p3->sum);
if(p2->hsh-p1->hsh==p4->hsh-p3->hsh) return p2->sum-p1->sum;
int mid=(L+R)>>1;
if(p2->Rh-p1->Rh!=p4->Rh-p3->Rh) return QueryR(p1->ch[1],p2->ch[1],p3->ch[1],p4->ch[1],mid+1,R);
else return QueryR(p1->ch[0],p2->ch[0],p3->ch[0],p4->ch[0],L,mid)+(p2->Rs-p1->Rs);
}
P_node rt[maxn];
int _test,n,Q;
int main(){
freopen("E.in","r",stdin);
freopen("E.out","w",stdout);
pw[0]=1; for(int i=1;i<=100002;i++) pw[i]=pw[i-1]*con;
scanf("%d",&_test);
while(_test--){
p_top=base;
scanf("%d%d",&n,&Q);
rt[0]=build(1,maxv);
for(int i=1;i<=n;i++){
int x; scanf("%d",&x);
rt[i]=Updata(rt[i-1],1,maxv,x);
}
while(Q--){
int t1,t2,t3,t4; scanf("%d%d%d%d",&t1,&t2,&t3,&t4);
int resL=QueryL(rt[t1-1],rt[t2],rt[t3-1],rt[t4],1,maxv);
int resR=QueryR(rt[t1-1],rt[t2],rt[t3-1],rt[t4],1,maxv);
if(resL==t2-t1+1||resL+resR+1==t2-t1+1) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}

本文介绍了一种结合主席树和哈希技术的算法实践,该方法能够高效地比较序列的相似性,并通过具体实现代码展示了如何在主席树上进行二分查找,找到序列中首次出现差异的位置。

被折叠的 条评论
为什么被折叠?



