分组

分组
题目描述
Bsny所在的精灵社区有n个居民,每个居民有一定的地位和年龄,ri表示第i个人的地位,ai表示第i个人的年龄。

最近社区里要举行活动,要求几个人分成一个小组,小组中必须要有一个队长,要成为队长有这样的条件:

1、队长在小组中的地位应该是最高的(可以并列第一);

2、小组中其他成员的年龄和队长的年龄差距不能超过K。

有些人想和自己亲密的人组在同一个小组,同时希望所在的小组人越多越好。比如x和y想在同一个小组,同时希望它们所在的小组人越多越好,当然,它们也必须选一个符合上述要求的队长,那么问你,要同时包含x和y的小组,最多可以组多少人?

输入
第一行两个整数n和K;

接下来一行输入n个整数:r1, r2, …, rn

接下来一行输入n个整数:a1, a2, …, an

接下来输入Q表示有Q个询问;

接下来Q行每行输入x, y,表示询问:当x和y组在同一个小组,它们小组最多可以有多少人(x和y也有可能被选为队长,只要它们符合条件)。

输出
对于每个询问,输出相应的答案,每个答案占一行。

当x和y无法在同一组时,输出-1(比如x的年龄是1, y的年龄是100,K=1,无论谁当队长,x和y两者中,总会有人跟队长的年龄差距超过K,那么输出-1)。

样例输入
5 1
1 5 4 1 2
4 4 3 2 2
4
5 3
2 3
2 5
4 1
样例输出
4
3
-1
4
提示
【样例解释】

询问1:当第5个人和第3个人想在一组时,小组成员可以有{1, 3, 4, 5},选择3当队长,而2不可以加入,因为2加入的话,5和2的年龄差距为2,超过K=1了;

询问2:当第2个人和第3个人想在一组时,可以选择{1, 2, 3};

询问3:当2和5想在一起时,无法满足要求;

询问4:当4和1想在一起时,可以选择{1, 3, 4, 5};

【数据规模】

20%的数据:2≤n≤100,0≤ k≤100,1≤ ri, ai ≤100,1≤ q≤ 100;

40%的数据:2≤ n≤1000,0≤ k≤ 1000,1≤ ri, ai ≤ 1000,1≤ q≤ 1000;

60%的数据:2≤ n≤ 104,0≤ k≤ 109,1≤ ri, ai ≤ 109, 1≤ q≤ 104;

100%的数据:2≤ n≤ 105,0≤ k≤ 109,1≤ ri, ai ≤ 109,1≤ q≤ 105,1≤ x, y≤ n, x≠y。

++线


r

[aik,ai+k]i

r

x,y,x,y

ar

a[max(x.ak,y.a+k),min(x.a+k,y.a+k)]

rr>=max(x.r,y.r)

a,r

线

rminrmax(x.r,y.r)

rmin

[max(x.ak,y.a+k),min(x.a+k,y.a+k)]

线

max(x.ak,y.a+k)>min(x.a+k,y.a+k)r1

O(nlogn)

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define lowbit(x) ((x)&(-x))
struct node{
  int r,a,v,id;
}num[100005],a[100005];
struct q_q{
    int x,y,z,id;
}q[100005];
int h[100005],d[100005],tree[400005];
int power[100005],age[100005],ans[100005];
bool cmp(node x,node y){
  return x.a<y.a;
}
bool CMP(node x,node y){
  return x.r<y.r;
}
int n,m,old;
void add(int x,int z){
  while (x<=old){
    h[x]+=z;
    x+=lowbit(x);
  }
}
int sum(int x){
  int he=0;
  while (x>0){
    he+=h[x];
    x-=lowbit(x);
  }
  return he;
}

int erfen(int l,int r,int x){
    if(l>r) return a[l].v;
    int mid=(l+r)>>1;
    if(x>a[mid].a) return erfen(mid+1,r,x); else return erfen(l,mid-1,x);
}
int ERFEN(int l,int r,int x){
    if(l>r) return a[r].v;
    int mid=(l+r)>>1;
    if(x>=a[mid].a) return ERFEN(mid+1,r,x); else return ERFEN(l,mid-1,x);
}
void prepare(){
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;++i){
    scanf("%d",&num[i].r);
    power[i]=num[i].r;
  }
  for (int i=1;i<=n;++i){
    scanf("%d",&num[i].a);
    age[i]=num[i].a;
    a[i].a=num[i].a;
    num[i].id=a[i].id=i;
  }
  sort(a+1,a+n+1,cmp);
  old=0;
  for (int i=1;i<=n;++i){
    if (a[i].a!=a[i-1].a)++old;
    num[a[i].id].v=old;
    a[i].v=old;
  }
  sort(num+1,num+n+1,CMP);
  int pre=1;
  num[0].r=-1;
  num[n+1].r=-1;
  for (int i=1;i<=n+1;++i){
    if (num[i].r!=num[i-1].r){
      for (int j=pre;j<i;++j){
        int down=max(1,erfen(1,n,num[j].a-m));
        int up=min(old,ERFEN(1,n,num[j].a+m));
        d[num[j].id]=sum(up)-sum(down-1);
      }
      pre=i;
    }
    if (i<n+1) add(num[i].v,1);
  }
}
bool haha(q_q x,q_q y){
  return x.z>y.z;
}
void update(int id,int l,int r,int x,int y){
    if(l==r){
        tree[id]=max(tree[id],y);
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) update(id+id,l,mid,x,y); 
    else update(id+id+1,mid+1,r,x,y);
    tree[id]=max(tree[id+id],tree[id+id+1]);
}
int query(int id,int l,int r,int x,int y){
    if(l>y||r<x) return 0;
    if(x<=l&&r<=y) return tree[id];
    int mid=(l+r)>>1;
    return max(query(id+id,l,mid,x,y),query(id+id+1,mid+1,r,x,y));
}
void solve(){
  int cas;
  scanf("%d",&cas);
  for (int i=1;i<=cas;++i){
    scanf("%d%d",&q[i].x,&q[i].y);
    q[i].z=max(power[q[i].x],power[q[i].y]);
    q[i].id=i;
  }
  sort(q+1,q+cas+1,haha);
  int tail=n;
  for (int i=1;i<=cas;++i){
    while (num[tail].r>=q[i].z){
      update(1,1,old,num[tail].v,d[num[tail].id]);
      tail--;
    }
    int x=q[i].x;
    int y=q[i].y;
    int down=max(1,erfen(1,n,max(age[x]-m,age[y]-m)));
    int up=min(old,ERFEN(1,n,min(age[x]+m,age[y]+m)));
    if(down<=up) ans[q[i].id]=query(1,1,old,down,up);
  }
  for (int i=1;i<=cas;++i) 
  if (ans[i]==0) printf("-1\n");
  else printf("%d\n",ans[i]);
}
int main(){
  prepare();
  solve();
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值