【NOIP2014八校联考第2场第2试9.28】分组(group)

Description

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

Solution

这题一看就是,裸的数据结构题,不过比较的麻烦。
首先要处理一个人当队长可以控制多少个人,排个序逐个插入权值线段树中,然后询问±k的年龄就可以了。这样处理出数组a表示当队长可以控制多少人。
处理完这个之后,我们就询问来看一看。
询问x,y,那么队长的年龄单位要满足两个人的要求,那么必须在两个人要求的交集里面,且这个队长的地位要≥这两个人的地位,且要找到最多可以控制的人数。
那么就很简单了,按照地位从大到小把人的a数组中的值逐个插进主席树中。
然后询问的时候,询问可行的年龄之间,且地位合法的主席树中的最大值。
要注意两个人的地位相同的情况。

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=1e5+7;
int i,j,k,l,n,m,ans,q,x,y,z,da,num,r;
int c[maxn],root[maxn],b[maxn],d[maxn],zuo[maxn];
struct nod{
    int r,a,c;
}a[maxn];
struct node{
    int l,r,mx,sum;
}t[maxn*40];
bool cmp(nod x,nod y){return x.r<y.r;} 
bool cmp1(nod x,nod y){return x.a<y.a;}
void insert(int &x,int l,int r,int y){
    if(!x)x=++num;
    if(l==r){t[x].sum++;return;}
    int mid=(l+r)/2;
    if(y<=mid)insert(t[x].l,l,mid,y);
    else insert(t[x].r,mid+1,r,y);
    t[x].sum=t[t[x].l].sum+t[t[x].r].sum;
}
void change(int o,int &x,int l,int r,int y,int z){
    x=++num,t[x]=t[o];
    if(l==r){t[x].mx=max(t[x].mx,z);return;}
    int mid=(l+r)/2;
    if(y<=mid)change(t[o].l,t[x].l,l,mid,y,z);
    else change(t[o].r,t[x].r,mid+1,r,y,z);
    t[x].mx=max(t[t[x].l].mx,t[t[x].r].mx);
}

int zhao(int x,int l,int r,int y,int z){
    if(!x)return 0;
    if(y>z)return 0;
    if(l==y&&r==z){
        return t[x].sum;
    }
    int mid=(l+r)/2;
    if(z<=mid)return zhao(t[x].l,l,mid,y,z);
    else if(y>mid)return zhao(t[x].r,mid+1,r,y,z);
    else return zhao(t[x].l,l,mid,y,mid)+zhao(t[x].r,mid+1,r,mid+1,z);
}
int find(int x,int l,int r,int y,int z){
    if(y>z)return 0;
    if(!x)return 0;
    if(l==y&&r==z){
        return t[x].mx;
    }
    int mid=(l+r)/2;
    if(z<=mid)return find(t[x].l,l,mid,y,z);
    else if(y>mid)return find(t[x].r,mid+1,r,y,z);
    else return max(find(t[x].l,l,mid,y,mid),find(t[x].r,mid+1,r,mid+1,z));
}
int main(){
//  freopen("fan.in","r",stdin);
    scanf("%d%d",&n,&k);
    fo(i,1,n)scanf("%d",&a[i].r),a[i].c=i;
    fo(i,1,n)scanf("%d",&a[i].a),da=max(a[i].a,da);
    sort(a+1,a+1+n,cmp1);
    sort(a+1,a+1+n,cmp);
    fo(i,1,n)d[a[i].c]=i;int u=1;
    i=1;num=1;
    while(i<=n){
         j=i;
         while(a[j].r==a[i].r)
         insert(u,1,da,a[j].a),j++;
         while(i<j){
             c[a[i].c]=zhao(u,1,da,max(1,a[i].a-k),min(da,a[i].a+k));
             i++;
        }
    }
    fo(i,1,num)t[x].l=t[x].r=t[x].sum=0;
    num=0;memset(root,0,sizeof(root));
    fod(i,n,1){
        change(root[i+1],root[i],1,da,a[i].a,c[a[i].c]);
    }
    fo(i,1,n){
        zuo[i]=i;
        while(zuo[i]>1&&a[zuo[i]-1].r==a[i].r)zuo[i]=zuo[zuo[i]-1];
    }
    for(scanf("%d",&q);q;q--){
        scanf("%d%d",&x,&y);
        r=min(a[d[x]].a,a[d[y]].a)+k;
        l=max(a[d[x]].a,a[d[y]].a)-k;
        if(l<1)l=1;if(r>da)r=da;
        z=zuo[max(d[x],d[y])];
        ans=find(root[z],1,da,l,r);
        if(!ans)ans=-1;
        printf("%d\n",ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值