【JZOJ 3854】 分组

35 篇文章 0 订阅
13 篇文章 0 订阅

Description

Bsny所在的精灵社区有n个居民,每个居民有一定的地位和年龄,ri表示第i个人的地位,ai表示第i个人的年龄。
最近社区里要举行活动,要求几个人分成一个小组,小组中必须要有一个队长,要成为队长有这样的条件:
1、队长在小组中的地位应该是最高的(可以并列第一);
2、小组中其他成员的年龄和队长的年龄差距不能超过K。
有些人想和自己亲密的人组在同一个小组,同时希望所在的小组人越多越好。比如x和y想在同一个小组,同时希望它们所在的小组人越多越好,当然,它们也必须选一个符合上述要求的队长,那么问你,要同时包含x和y的小组,最多可以组多少人?

100%的数据:2≤ n≤ 10^5,0≤ k≤ 10^9,1≤ ri, ai ≤ 10^9,1≤ q≤ 10^5,1≤ x, y≤ n, x≠y。

Analysis

这里简单记录下思路
先离散化
预处理出每个人作为队长能组多少人,可以用BIT快速求
然后,离线,将询问按max(r[x],r[y])从大到小拍,用权值线段树来维护

Code

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int N=300010;
struct node
{
    int r,age,la,ra,id;
}a[N];
struct lyd
{
    int x,y,z,id;
}b[N],d[N];
int n,m,mx,k,tot,s[N],c[N],BIT[N],ans[N],tr[N*4];
bool cmp(lyd a,lyd b)
{
    return a.x<b.x;
}
void pre()
{
    scanf("%d %d",&n,&k);
    fo(i,1,n) scanf("%d",&a[i].r),a[i].id=i;
    fo(i,1,n)
    {
        scanf("%d",&a[i].age),a[i].la=a[i].age-k,a[i].ra=a[i].age+k;
        d[++tot].x=a[i].age,d[tot].y=i,d[tot].z=0;
        d[++tot].x=a[i].la,d[tot].y=i,d[tot].z=1;
        d[++tot].x=a[i].ra,d[tot].y=i,d[tot].z=2;
    }
    d[0].x=-2147483647;
    sort(d+1,d+tot+1,cmp);
    fo(i,1,tot)
    {
        int j=d[i].y;
        if(d[i].x!=d[i-1].x) mx++;
        if(d[i].z==0) a[j].age=mx;
        if(d[i].z==1) a[j].la=mx;
        if(d[i].z==2) a[j].ra=mx;
    }
    tot=0;
}
bool cmp1(node a,node b)
{
    return a.r<b.r;
}
bool cmp2(lyd a,lyd b)
{
    return a.z>b.z;
}
int lowbit(int x)
{
    return x&-x;
}
int get(int x)
{
    int t=0;
    for(int i=x;i;i-=lowbit(i)) t+=BIT[i];
    return t;
}
void add(int x)
{
    for(int i=x;i<=mx;i+=lowbit(i)) BIT[i]++;
}
void change(int v,int l,int r,int x,int z)
{
    if(l==r)
    {
        tr[v]=max(tr[v],z);
        return;
    }
    int mid=(l+r)>>1;
    if(x<=mid) change(v+v,l,mid,x,z);
    else change(v+v+1,mid+1,r,x,z);
    tr[v]=max(tr[v+v],tr[v+v+1]);
}
int find(int v,int l,int r,int x,int y)
{
    if(l==x && r==y) return tr[v];
    int mid=(l+r)>>1;
    if(y<=mid) return find(v+v,l,mid,x,y);
    else
    if(x>mid) return find(v+v+1,mid+1,r,x,y);
    else
    return max(find(v+v,l,mid,x,mid),find(v+v+1,mid+1,r,mid+1,y));
}
int main()
{
    pre();
    sort(a+1,a+n+1,cmp1);
    int st=1;
    fo(i,1,n)
    {
        if(i!=1 && a[i].r!=a[i-1].r)
        {
            fo(j,st,i-1) s[j]=get(a[j].ra)-get(a[j].la-1);
            st=i;
        }
        c[a[i].id]=i;
        add(a[i].age);
    }
    fo(j,st,n) s[j]=get(a[j].ra)-get(a[j].la-1);
    scanf("%d",&m);
    fo(i,1,m)
    {
        scanf("%d %d",&b[i].x,&b[i].y),b[i].id=i;
        b[i].x=c[b[i].x],b[i].y=c[b[i].y];
        b[i].z=max(a[b[i].x].r,a[b[i].y].r);
    }
    sort(b+1,b+m+1,cmp2);
    int j=n;
    fo(i,1,m)
    {
        while(a[j].r>=b[i].z) change(1,1,mx,a[j].age,s[j]),j--;
        int x=b[i].x,y=b[i].y;
        if(a[x].age>a[y].age) swap(x,y);
        if(a[x].ra<a[y].la) ans[b[i].id]=-1;
        else
        {
            int p=find(1,1,mx,a[y].la,a[x].ra);
            if(p) ans[b[i].id]=p;
            else ans[b[i].id]=-1;
        }
    }
    fo(i,1,m) printf("%d\n",ans[i]);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值