[主席树+哈希] Codechef June Challenge 2017 #CLONEME

主席树+哈希套路。通过哈希做到快速比较一些东西是否相等,很可能和字典序什么的有关。

这题就是利用哈希,在主席树上二分一样地走,找到从左边开始第一个不一样的和从右边开始第一个不一样的,然后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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值