分组 题目描述 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进行从小到大排序 我们可以从小到大遍历每个人,利用树状数组统计[ai−k,ai+k]的人数,即为第i个人作为队长最大组队人数 这里要对相同r的时候特殊处理一下 然后,对于一组询问x,y,我们可以计算出能包含x,y的组 队长的a和r的限制条件 即a的范围为[max(x.a−k,y.a+k),min(x.a+k,y.a+k)] r的范围为r>=max(x.r,y.r) 我们可以在符合a,r范围的所有人中寻找最大值 但考虑到询问比较大,我们可以采取离线的方式处理询问: 用rmin表示满足询问r的最小值,即max(x.r,y.r) 对询问根据rmin从大到小排序 再求[max(x.a−k,y.a+k),min(x.a+k,y.a+k)]范围中最大值是多少 这个可以用线段树来维护和求解 如果max(x.a−k,y.a+k)>min(x.a+k,y.a+k)或者找不到符合r的人,那么答案为−1 因此,总的复杂度为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; }