#树状数组,线段树,离散#JZOJ 3854 分组
题目
Bsny所在的精灵社区有\(n\)个居民,每个居民有一定的地位和年龄,\(r_i\)表示第\(i\)个人的地位,\(a_i\)表示第\(i\)个人的年龄。
最近社区里要举行活动,要求几个人分成一个小组,小组中必须要有一个队长,要成为队长有这样的条件:
1、队长在小组中的地位应该是最高的(可以并列第一);
2、小组中其他成员的年龄和队长的年龄差距不能超过\(K\)。
有些人想和自己亲密的人组在同一个小组,同时希望所在的小组人越多越好。比如\(x\)和\(y\)想在同一个小组,同时希望它们所在的小组人越多越好,当然,它们也必须选一个符合上述要求的队长,那么问你,要同时包含\(x\)和\(y\)的小组,最多可以组多少人?
第一行两个整数\(n\)和\(K\);
接下来一行输入\(n\)个整数:\(r_1, r_2,\dots, r_n\)
接下来一行输入\(n\)个整数:\(a_1, a_2,\dots, a_n\)
接下来输入\(Q\)表示有\(Q\)个询问;
接下来\(Q\)行每行输入\(x, y\),表示询问:当\(x\)和\(y\)组在同一个小组,它们小组最多可以有多少人(\(x\)和\(y\)也有可能被选为队长,只要它们符合条件)。
对于每个询问,输出相应的答案,每个答案占一行。
当\(x\)和\(y\)无法在同一组时,输出-1(比如\(x\)的年龄是1, \(y\)的年龄是100,\(K=1\),无论谁当队长,\(x\)和\(y\)两者中,总会有人跟队长的年龄差距超过\(K\),那么输出-1)。
Sample Input
5 1
1 5 4 1 2
4 4 3 2 2
4
5 3
2 3
2 5
4 1
Sample Output
4
3
-1
4
分析
对于地位最高这个条件可以离线处理,枚举队长是谁以处理询问
先将年龄离散化,那么这个队长可以选的区间就是\([a_x-k\sim a_x+k]\)
答案就是两人选择区间的交集大小,可以用树状数组+线段树实现
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <vector>
#define rr register
using namespace std;
const int N=100011;
struct rec{int w,c,rk;}a[N];
int n,m,b[N],k,l[N],r[N],pos[N],ans[N],Rk[N],bas=1; vector<int>K[N];
inline signed min(int a,int b){return a<b?a:b;}
inline signed max(int a,int b){return a>b?a:b;}
struct zkw{
int w[N*3];
inline void build(int n){
for (;(bas<<=1)<n+2;);
for (rr int i=1;i<=bas*2;++i) w[i]=-1;
}
inline void update(int x,int z){
x+=bas,w[x]=max(w[x],z);
for (x>>=1;x;x>>=1) w[x]=max(w[x<<1],w[x<<1|1]);
}
inline signed query(int l,int r){
rr int ans=-1;
for (l+=bas-1,r+=bas+1;l^r^1;l>>=1,r>>=1){
if (!(l&1)) ans=max(ans,w[l^1]);
if (r&1) ans=max(ans,w[r^1]);
}
return ans;
}
}T;
struct Tree_Array{
int c[N];
inline void update(int x,int y){
for (;x<=n;x+=-x&x) c[x]+=y;
}
inline signed query(int x){
rr int ans=0;
for (;x;x-=-x&x) ans+=c[x];
return ans;
}
}C;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans<0) putchar('-'),ans=-ans;
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
bool cmp(rec x,rec y){return x.c>y.c;}
signed main(){
n=iut(),k=iut();
for (rr int i=1;i<=n;++i) a[i].c=iut(),a[i].rk=i;
for (rr int i=1;i<=n;++i) a[i].w=iut(),b[i]=a[i].w;
sort(b+1,b+1+n),m=unique(b+1,b+1+n)-b-1,sort(a+1,a+1+n,cmp),T.build(m);
for (rr int i=1;i<=n;++i){
l[i]=lower_bound(b+1,b+1+m,a[i].w-k)-b,r[i]=upper_bound(b+1,b+1+m,a[i].w+k)-b-1;
Rk[a[i].rk]=i,C.update(a[i].w=lower_bound(b+1,b+1+m,a[i].w)-b,1);
}
rr int Test=iut();
for (rr int i=1;i<=Test;++i){
rr int x=Rk[iut()],y=Rk[iut()];
if (x<y) x^=y,y^=x,x^=y;
K[y].push_back(i),pos[i]=x;
}
for (rr int i=1,p=1;i<=n;++i){
for (;p<=n&&a[p].c>=a[i].c;++p) T.update(a[p].w,C.query(r[p])-C.query(l[p]-1));
for (rr int j=0;j<K[i].size();++j){
rr int x=pos[K[i][j]],y=i;
rr int L=max(l[x],l[y]),R=min(r[x],r[y]);
if (L>R) ans[K[i][j]]=-1;
else ans[K[i][j]]=T.query(L,R);
}
C.update(a[i].w,-1);
}
for (rr int i=1;i<=Test;++i) print(ans[i]),putchar(10);
return 0;
}