loj#6169. 相似序列

来源:互联网 发布:linux 注销登录用户 编辑:程序博客网 时间:2024/05/13 16:54

最近口胡了一个随机的idea,结果在loj上连出3道类似的题。。

我的思路是这样的:给每个数一个随机权值,如果两个序列的数的随机权值异或和相等可以认为这两个序列排序后相同。考虑主席树,对于两个区间l~r的数,二分一个将那对不同的数分开的数值,然后用区间最大(小)查询就能得到那两个不同的数,再判断一下即可。

复杂度由于在线段树上二分,复杂度O(nlogn)。

至于那个随机为什么对,只要考虑如果两个序列相等,异或和必定相等,否则最后的异或和是随机的,有2^-64相同,(1-2^-64)^(nlogn)的概率正确。//大概算出来是这个东西:


UPD:被hack了,请把异或和改为和。

#include<bits/stdc++.h>#define ll long long#define N 100005#define M 100000using namespace std;int T,n,q,a[N],Rt[N];int ls[2000005],rs[2000005],cnt,sz[2000005];ll v[2000005],b[N];ll rd(){return ((ll)rand()<<48LL)|((ll)rand()<<32LL)|((ll)rand()<<16LL)|rand();}void add(int p,int &q,int l,int r,int x){q=++cnt;v[q]=v[p]^b[x];sz[q]=sz[p]+1;ls[q]=rs[q]=0;if (l==r)return;int mid=l+r>>1;if (x<=mid) rs[q]=rs[p],add(ls[p],ls[q],l,mid,x);else ls[q]=ls[p],add(rs[p],rs[q],mid+1,r,x);}int qMx(int x,int y,int l,int r){if (l==r) return l;int mid=l+r>>1;if (sz[rs[x]]!=sz[rs[y]]) return qMx(rs[x],rs[y],mid+1,r);return qMx(ls[x],ls[y],l,mid);}int qMn(int x,int y,int l,int r){if (l==r) return l;int mid=l+r>>1;if (sz[ls[x]]!=sz[ls[y]]) return qMn(ls[x],ls[y],l,mid);return qMn(rs[x],rs[y],mid+1,r);}bool check(int l1,int r1,int l2,int r2){int l=1,r=M,mid;l1=Rt[l1-1];r1=Rt[r1];l2=Rt[l2-1];r2=Rt[r2];if ((v[r1]^v[l1])==(v[r2]^v[l2])&&sz[r1]-sz[l1]==sz[r2]-sz[l2]) return 1;while(l<r){mid=l+r>>1;if ((v[ls[r1]]^v[ls[l1]])==(v[ls[r2]]^v[ls[l2]])&&sz[ls[r1]]-sz[ls[l1]]==sz[ls[r2]]-sz[ls[l2]])r1=rs[r1],l1=rs[l1],r2=rs[r2],l2=rs[l2],l=mid+1;else if ((v[rs[r1]]^v[rs[l1]])==(v[rs[r2]]^v[rs[l2]])&&sz[rs[r1]]-sz[rs[l1]]==sz[rs[r2]]-sz[rs[l2]])r1=ls[r1],l1=ls[l1],r2=ls[r2],l2=ls[l2],r=mid;else{if ((sz[ls[r1]]-sz[ls[l1]])-(sz[ls[r2]]-sz[ls[l2]])==-1)swap(l1,l2),swap(r1,r2);if ((sz[ls[r1]]-sz[ls[l1]])-(sz[ls[r2]]-sz[ls[l2]])==1)if ((v[r1]^v[l1]^b[qMx(ls[l1],ls[r1],l,mid)])==(v[r2]^v[l2]^b[qMn(rs[l2],rs[r2],mid+1,r)]))return 1;return 0;}}return 1;}void work(){cnt=0;scanf("%d%d",&n,&q);for (int i=1;i<=n;i++){scanf("%d",&a[i]);add(Rt[i-1],Rt[i],1,M,a[i]);}for (int i=1;i<=q;i++){int l1,l2,r1,r2;scanf("%d%d%d%d",&l1,&r1,&l2,&r2);puts(check(l1,r1,l2,r2)?"YES":"NO");}}int main(){srand(time(0));for (int i=1;i<=M;i++)b[i]=rd();sort(b+1,b+M+1);for (int i=1;i<=M;i++)b[i]+=i;random_shuffle(b+1,b+M+1);scanf("%d",&T);while(T--) work();}


原创粉丝点击