[主席树维护HASH] Codechef. Cloning

传送门

直接用主席树维护HASH比较就可以了吧…

#include <cstdio>
#include <algorithm>
#include <iostream>

using namespace std;

typedef unsigned long long ll;

const int N=100010;
const ll base=100003;

int t,n,q,cnt;
int a[N],rt[N],ls[N*50],rs[N*50],tot[N*50];
ll v[N*50],p[N];

void Add(int &g,int l,int r,int x){
  int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k]; v[g]=v[k]; tot[g]=tot[k];
  if(l==r){
    v[g]++; tot[g]++; return ;
  }
  int mid=l+r>>1;
  if(x<=mid) Add(ls[g],l,mid,x); else Add(rs[g],mid+1,r,x);
  v[g]=v[ls[g]]*p[r-mid]+v[rs[g]]; tot[g]=tot[ls[g]]+tot[rs[g]];
}

inline int dif(int x,int y,int a,int b){
  if(v[y]-v[x]==v[b]-v[a]) return 0;
  int l=1,r=n;
  while(l<r){
    int mid=l+r>>1;
    if(v[ls[y]]-v[ls[x]]==v[ls[b]]-v[ls[a]])
      x=rs[x],y=rs[y],a=rs[a],b=rs[b],l=mid+1;
    else
      x=ls[x],y=ls[y],a=ls[a],b=ls[b],r=mid;
  }
  return l;
}

int Find(int x,int y,int L,int R,int l,int r){
  if(v[x]-v[y]==0) return -1;
  if(L==R) return tot[x]-tot[y]==0?-1:L;
  int mid=L+R>>1;
  if(l==L && r==R){
    if(v[ls[x]]-v[ls[y]]) return Find(ls[x],ls[y],L,mid,l,mid);
    else return Find(rs[x],rs[y],mid+1,R,mid+1,r);
  }
  if(r<=mid) return Find(ls[x],ls[y],L,mid,l,r);
  else if(l>mid) return Find(rs[x],rs[y],mid+1,R,l,r);
  int ret=Find(ls[x],ls[y],L,mid,l,mid);
  if(~ret) return ret;
  return Find(rs[x],rs[y],mid+1,R,mid+1,r);
}

int Check(int x,int y,int L,int R,int p){
  if(L==R) return tot[x]-tot[y];
  int mid=L+R>>1;
  if(p<=mid) return Check(ls[x],ls[y],L,mid,p);
  else return Check(rs[x],rs[y],mid+1,R,p);
}

int main(){
  scanf("%d",&t);
  p[0]=1; for(int i=1;i<=100000;i++) p[i]=p[i-1]*base;
  while(t--){
    scanf("%d%d",&n,&q); cnt=0;
    for(int i=1;i<=n;i++) rt[i]=0;
    for(int i=1;i<=n;i++){
      scanf("%d",&a[i]); rt[i]=rt[i-1];
      Add(rt[i],1,n,a[i]);
    }
    for(int i=1;i<=q;i++){
      int l1,r1,l2,r2;
      scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
      int pos=dif(rt[l1-1],rt[r1],rt[l2-1],rt[r2]);
      if(!pos){
    puts("YES");
    continue;
      }
      int A=Check(rt[r1],rt[l1-1],1,n,pos),B=Check(rt[r2],rt[l2-1],1,n,pos);
      if(A>B){
    A=Find(rt[r1],rt[l1-1],1,n,pos,n); B=Find(rt[r2],rt[l2-1],1,n,pos+1,n);
      }
      else{
    A=Find(rt[r1],rt[l1-1],1,n,pos+1,n); B=Find(rt[r2],rt[l2-1],1,n,pos,n);
      }
      int curA=rt[r1],curB=rt[r2],lst=cnt;
      if(~A) Add(curB,1,n,A);
      if(~B) Add(curA,1,n,B);
      if(!dif(rt[l1-1],curA,rt[l2-1],curB)) puts("YES");
      else puts("NO");
      cnt=lst;
    }
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值