#树状数组,线段树,离散#JZOJ 3854 分组 From 2020.01.16【NOIP提高组】模拟A 组

廉价感情. 提交于 2020-02-15 19:16:53

题目

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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!