[主席树 Hash] Codechef JUNE17 #CLONEME Cloning

对权值建主席树 然后对于区间[a,b],[c,d]
在主席树上二分排完序后从左第一个不一样的地方 以及从右第一个不一样的地方
这个可以Hash下权值的出现次数,也是可以相减的

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef unsigned long long ull;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=100005;
const int M=10000005;
const int maxn=1e5;

int rt[N],ncnt;
int ls[M],rs[M];
ull H[M]; int sum[M];

ull seed[N];

inline void add(int &x,int y,int l,int r,int t){
  x=++ncnt;
  if (l==r){
    sum[x]=sum[y]+1; H[x]=sum[x]; return;
  }
  int mid=(l+r)>>1;
  if (t<=mid) add(ls[x],ls[y],l,mid,t),rs[x]=rs[y];
  else add(rs[x],rs[y],mid+1,r,t),ls[x]=ls[y];
  H[x]=H[ls[x]]+seed[mid-l+1]*H[rs[x]];
  sum[x]=sum[ls[x]]+sum[rs[x]];
}

int Ret=0;

inline void queryL(int a,int b,int c,int d,int l,int r){
  if (H[b]-H[a]==H[d]-H[c]){ Ret+=sum[b]-sum[a]; return; }
  if (l==r){
    Ret+=min(sum[b]-sum[a],sum[d]-sum[c]);
    return;
  }
  int mid=(l+r)>>1;
  if (H[ls[b]]-H[ls[a]]==H[ls[d]]-H[ls[c]]){
    Ret+=sum[ls[b]]-sum[ls[a]];
    queryL(rs[a],rs[b],rs[c],rs[d],mid+1,r);
  }else
    queryL(ls[a],ls[b],ls[c],ls[d],l,mid);
}

inline void queryR(int a,int b,int c,int d,int l,int r){
  if (H[b]-H[a]==H[d]-H[c]){ Ret+=sum[b]-sum[a]; return; }
  if (l==r){
    Ret+=min(sum[b]-sum[a],sum[d]-sum[c]);
    return;
  }
  int mid=(l+r)>>1;
  if (H[rs[b]]-H[rs[a]]==H[rs[d]]-H[rs[c]]){
    Ret+=sum[rs[b]]-sum[rs[a]];
    queryR(ls[a],ls[b],ls[c],ls[d],l,mid);
  }else
    queryR(rs[a],rs[b],rs[c],rs[d],mid+1,r);
}


int n,val[N];

int main(){
  int T;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(T); seed[0]=1; for (int i=1;i<=maxn;i++) seed[i]=seed[i-1]*233333;
  while (T--){
    ncnt=0; int Q,a,b,c,d;
    read(n); read(Q);
    for (int i=1;i<=n;i++)
      read(val[i]),add(rt[i],rt[i-1],1,maxn,val[i]);
    while (Q--){
      read(a); read(b); read(c); read(d);
      int lret,rret;
      Ret=0;
      queryL(rt[a-1],rt[b],rt[c-1],rt[d],1,maxn);
      lret=Ret;
      Ret=0;
      queryR(rt[a-1],rt[b],rt[c-1],rt[d],1,maxn);
      rret=Ret;

      if ((lret==b-a+1) || (lret+rret+1==b-a+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、付费专栏及课程。

余额充值