jzoj3854-分组【树状数组,线段树】

正题

题目链接:https://jzoj.net/senior/#contest/show/2990/2


题目大意

一个小队满足要求

  1. 队长的地位最高
  2. 所有队员和队长的年龄差不超过kk

给出nn个人的地位和年龄,qq个询问

每次询问一组(x,y)(x,y)求若(x,y)(x,y)在同一个队里那这个队的最多人数。


解题思路

我们将年龄离散化然后按照地位从大到小排序。

然后我们用树状数组维护出每个人作为队长时小队的最多人数。

之后我们对于每个询问(x,y)(x,y),默认yy的地位大于xx

我们按照地位从大到小枚举,对于每个(x,y)(x,y),我们搞定满足条件的年龄范围(l,r)(l,r),然后将地位比yy大的最多人数都丢进线段树里,然后查询区间(l,r)(l,r)即可。


codecode

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=1e5+10;
struct node{
	int r,w,num;
}a[N];
int n,k,Q,cnt,ans[N];
int b[N],num[N],l[N],r[N],v[N];
vector<int> q[N];
struct Tree_Array{
	#define lowbit(x) (x&-x)
	int t[N];
	void Change(int x,int z){
		while(x<=n){
			t[x]+=z;
			x+=lowbit(x);
		}
		return;
	}
	int Ask(int x){
		int ans=0;
		while(x){
			ans+=t[x];
			x-=lowbit(x);
		}
		return ans;
	}
	#undef lowbit(x)
}TA;
struct Seq_Tree{
	struct Tree_node{
		int l,r,w;
	}t[N*4];
	void Build(int x,int l,int r){
		t[x].l=l;t[x].r=r;t[x].w=-1;
		if(l==r)return;
		int mid=(l+r)/2;
		Build(x*2,l,mid);
		Build(x*2+1,mid+1,r);
	}
	void Change(int x,int pos,int z){
		if(t[x].l==t[x].r){
			t[x].w=max(t[x].w,z);
			return;
		}
		int mid=(t[x].l+t[x].r)>>1;
		if(pos<=mid) Change(x*2,pos,z);
		else Change(x*2+1,pos,z);
		t[x].w=max(t[x*2].w,t[x*2+1].w);
	}
	int Ask(int x,int l,int r){
		if(t[x].l==l&&t[x].r==r)
			return t[x].w;
		int mid=(t[x].l+t[x].r)>>1;
		if(r<=mid) return Ask(x*2,l,r);
		if(l>mid) return Ask(x*2+1,l,r);
		return max(Ask(x*2,l,mid),Ask(x*2+1,mid+1,r));
	}
}T;
bool cmp(node x,node y)
{return x.r>y.r;}
int main()
{
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i].r),a[i].num=i;
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i].w),b[++cnt]=a[i].w;
	sort(b+1,b+1+cnt);
	cnt=unique(b+1,b+1+cnt)-b-1;
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++){
		num[a[i].num]=i;
		l[i]=lower_bound(b+1,b+1+cnt,a[i].w-k)-b;
		r[i]=upper_bound(b+1,b+1+cnt,a[i].w+k)-b-1;
		a[i].w=lower_bound(b+1,b+1+cnt,a[i].w)-b;
		TA.Change(a[i].w,1);
	}
	scanf("%d",&Q);
	for(int i=1;i<=Q;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		x=num[x];y=num[y];
		if(x<y)swap(x,y);
		q[y].push_back(i);
		v[i]=x;
	}
	int w=1;T.Build(1,1,cnt);
	for(int i=1;i<=n;i++){
		while(w<=n&&a[w].r>=a[i].r){
			int val=TA.Ask(r[w])-TA.Ask(l[w]-1);
			T.Change(1,a[w].w,val);w++;
		}
		for(int j=0;j<q[i].size();j++){
			int x=v[q[i][j]],y=i;
			int L=max(l[x],l[y]),R=min(r[x],r[y]);
			if(L>R)	ans[q[i][j]]=-1;
			else ans[q[i][j]]=T.Ask(1,L,R);
		}
		TA.Change(a[i].w,-1);
	}
	for(int i=1;i<=Q;i++)
		printf("%d\n",ans[i]);
}
发布了852 篇原创文章 · 获赞 55 · 访问量 8万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 精致技术 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览