zoukankan      html  css  js  c++  java
  • LOJ6169 相似序列

    相似序列

    给定长度为 (n) 的整数序列 (A),你需要回答 (q) 个询问。询问给定两个子串 ([a, b])([c, d]),要求你判断两个子串是否相似。

    如果两个序列在各自排序后,除最多一个位置外,其他所有位置上的元素对应相等,那么我们认为两个序列相似。

    请注意,给定的子串可以有公共部分,但不会互相影响。

    (1 leq n,q leq 10 ^ 5)

    题解

    http://jklover.hs-blog.cf/2020/05/28/Loj-6169-相似序列/#more

    Hash + 主席树.

    给每种元素随机分配一个大权值,若两个区间内权值和相等,就可以认为它们在排序后是一样的.

    现在可以允许排序后有一个位置不同.

    以权值为下标建出主席树,二分出第一个不能匹配的权值 (x) ,最后一个不能被匹配的权值 (y) .

    (x,y) 是来自两个不同的子串,且 ([x,y]) 内没有其它权值,说明排序后它们位置能对应上,两个子串就相似了.

    可以记录一下每种权值的个数,方便判断.

    时间复杂度 (O(nlog n)) .

    IN uint64 gen(){
    	uint64 a=rand(),b=rand(),c=rand(),d=rand();
    	return a|b<<15|c<<30|d<<45;
    }
    
    CO int N=1e5+10;
    int a[N];
    uint64 val[N],b[N];
    int root[N],tot;
    int lc[N*20],rc[N*20],cnt[N*20];
    uint64 sum[N*20];
    
    #define mid ((l+r)>>1)
    void insert(int&x,int l,int r,int p,uint64 v){
    	++tot,lc[tot]=lc[x],rc[tot]=rc[x];
    	cnt[tot]=cnt[x]+1,sum[tot]=sum[x]+v,x=tot;
    	if(l==r) return;
    	if(p<=mid) insert(lc[x],l,mid,p,v);
    	else insert(rc[x],mid+1,r,p,v);
    }
    pair<int,int> query_first(int A,int B,int C,int D,int l,int r){
    	if(l==r){
    		if(sum[B]-sum[A]==sum[D]-sum[C]) return {-1,0};
    		return {l,cnt[B]-cnt[A]-(cnt[D]-cnt[C])};
    	}
    	if(sum[lc[B]]-sum[lc[A]]!=sum[lc[D]]-sum[lc[C]])
    		return query_first(lc[A],lc[B],lc[C],lc[D],l,mid);
    	else
    		return query_first(rc[A],rc[B],rc[C],rc[D],mid+1,r);
    }
    pair<int,int> query_last(int A,int B,int C,int D,int l,int r){
    	if(l==r){
    		if(sum[B]-sum[A]==sum[D]-sum[C]) return {-1,0};
    		return {l,cnt[B]-cnt[A]-(cnt[D]-cnt[C])};
    	}
    	if(sum[rc[B]]-sum[rc[A]]!=sum[rc[D]]-sum[rc[C]])
    		return query_last(rc[A],rc[B],rc[C],rc[D],mid+1,r);
    	else
    		return query_last(lc[A],lc[B],lc[C],lc[D],l,mid);
    }
    int query_cnt(int A,int B,int C,int D,int l,int r,int ql,int qr){
    	if(ql<=l and r<=qr) return cnt[B]-cnt[A]+cnt[D]-cnt[C];
    	if(qr<=mid)
    		return query_cnt(lc[A],lc[B],lc[C],lc[D],l,mid,ql,qr);
    	if(ql>mid)
    		return query_cnt(rc[A],rc[B],rc[C],rc[D],mid+1,r,ql,qr);
    	return query_cnt(lc[A],lc[B],lc[C],lc[D],l,mid,ql,qr)+query_cnt(rc[A],rc[B],rc[C],rc[D],mid+1,r,ql,qr);
    }
    bool check(int A,int B,int C,int D){
    	if(B-A!=D-C) return 0;
    	pair<int,int> x=query_first(root[A-1],root[B],root[C-1],root[D],1,1e5);
    	if(x.first==-1) return 1;
    	pair<int,int> y=query_last(root[A-1],root[B],root[C-1],root[D],1,1e5);
    	if(x.first==y.first) return 1;
    	if((x.second>0)==(y.second>0)) return 0;
    	if(abs(x.second)>1 or abs(y.second)>1) return 0;
    	if(x.first+1>y.first-1) return 1;
    	return query_cnt(root[A-1],root[B],root[C-1],root[D],1,1e5,x.first+1,y.first-1)==0;
    }
    #undef mid
    
    void real_main(){
    	tot=0;
    	for(int i=1;i<=1e5;++i) val[i]=gen();
    	int n=read<int>(),q=read<int>();
    	for(int i=1;i<=n;++i){
    		read(a[i]),b[i]=val[a[i]];
    		insert(root[i]=root[i-1],1,1e5,a[i],b[i]);
    	}
    	while(q--){
    		int A=read<int>(),B=read<int>(),C=read<int>(),D=read<int>();
    		puts(check(A,B,C,D)?"YES":"NO");
    	}
    }
    int main(){
    	srand(20030506);
    	for(int T=read<int>();T--;) real_main();
    	return 0;
    }
    
  • 相关阅读:
    利用序列化进行深度克隆
    原型链
    本地储存cookie,localStorage,sessionStorage
    ES6创建类
    hexo基本命令
    mouseent和mouseover的区别
    Event
    offset,client,scroll
    字符串的常用方法
    数组去重
  • 原文地址:https://www.cnblogs.com/autoint/p/13039813.html
Copyright © 2011-2022 走看看