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

DescriptionDescription

定义一个合法的集合为:集合里所有元素的AgeAgeRankRank最大的那个差不大于kk

给定nn个人的RankRankAgeAge,有QQ组询问,每次询问包含(x,y)(x,y)在内的符合要求的最大集合大小

数据范围:n105;k109;Age,Rank109n\leq 10^5;k\leq 10^9;Age,Rank\leq 10^9


SolutionSolution

首先求出每个人是最年长者时的最大集合大小(树状数组),查询即为在一个合法的集合中查找某个年龄段的最大值(线段树)

离散化处理即可,时间复杂度:O((n+Q)logn)O((n+Q)logn)

一些预处理的方法:

首先排序对年龄AA从大到小排序,由于我们要用树状数组,所以要离散化
定义以下数组:
num[i]num[i]表示原来位置为ii的数的新位置
L[i]L[i]表示排名为ii(即排序后的AA对应的位置)年龄至少比它小kk岁的排名(查询p[i].akp[i].a-k的前驱往后一个即可)
R[i]R[i]表示排名为ii,年龄最后一个比它大kk岁的排名(查询p[i].a+kp[i].a+k的后继往前一个即可)

然后将询问处理,由于询问较多,得用vectorvector,但这样子二元组比较麻烦,可以开一个辅助数组帮助记忆
然后处理每个人作为队长的,记为nlnl,找出尽量大的nrnr使得nrnr的地位比nlnl高,然后树状数组查询nrnr作为最大值的集合大小,由于我们地位是从大到小排序的,这样保证先加进来的一定可以做后面的元素的最大值,直接对应询问查询即可

注意:答案为0即是答案为-1


CodeCode

#include<cctype>
#include<cstdio>
#include<vector>
#include<algorithm>
#define LL long long
#define N 100010
using namespace std;int n,m,k,A[N],Q,x,y,f[N],zz[N],L[N],R[N],res[N],v[N],nl,nr;
struct node{int r,a,id;}p[N];
inline bool cmp(node x,node y){return x.r>y.r;}
inline LL read()
{
	char c;LL d=1,f=0;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
struct szsz
{
	int c[N];
	inline void add(int x,int d){for(;x<=n;x+=x&-x)c[x]+=d;return;}
	inline int ask(int x){int ans=0;for(;x;x-=x&-x)ans+=c[x];return ans;}
}TA;
struct xds
{
	#define lson k<<1
	#define rson k<<1|1
	int dat[N<<3];
	inline void up(int k){dat[k]=max(dat[lson],dat[rson]);return;}
	inline int Query(int ql,int qr,int k=1,int l=1,int r=n)
	{
		if(ql<=l&&r<=qr) return dat[k];
		int mid=l+r>>1,Ans=0;
		if(ql<=mid) Ans=max(Ans,Query(ql,qr,lson,l,mid));
		if(qr>mid) Ans=max(Ans,Query(ql,qr,rson,mid+1,r));
		return Ans;
	}
	inline void Modify(int x,int d,int k=1,int l=1,int r=n)
	{
		if(l==r) {dat[k]=max(dat[k],d);return;}
		int mid=l+r>>1;
		if(x<=mid) Modify(x,d,lson,l,mid);else Modify(x,d,rson,mid+1,r);
		up(k);
		return;
	}
	#undef lson
	#undef rson
}T;
vector<int>q[N];
signed main()
{
	m=n=read();k=read();
	for(register int i=1;i<=n;i++) p[i].r=read(),p[i].id=i;
	for(register int i=1;i<=n;i++) A[i]=p[i].a=read();
	sort(A+1,A+1+m);m=unique(A+1,A+1+m)-A-1;
	sort(p+1,p+1+n,cmp);
	for(register int i=1;i<=n;i++)
	{
		zz[p[i].id]=i;
		L[i]=lower_bound(A+1,A+1+m,p[i].a-k)-A;
		R[i]=upper_bound(A+1,A+1+m,p[i].a+k)-A-1;
		p[i].a=lower_bound(A+1,A+1+m,p[i].a)-A;
		TA.add(p[i].a,1);
	}
	Q=read();
	for(register int i=1;i<=Q;i++)
	{
		x=zz[read()];y=zz[read()];
		if(x<y) swap(x,y);
		q[y].push_back(i);
		v[i]=x;
	}
	for(nl=nr=1;nl<=n;nl++)
	{
		while(nr<=n&&p[nr].r>=p[nl].r)
		{
			int val=TA.ask(R[nr])-TA.ask(L[nr]-1);
			T.Modify(p[nr++].a,val);
		}
		for(register int j=0;j<q[nl].size();j++)
		{
			int i=q[nl][j],x=v[i],y=nl;
			int ql=max(L[x],L[y]),qr=min(R[x],R[y]);
			if(ql>qr) res[i]=-1;
			else res[i]=T.Query(ql,qr);
		}
		TA.add(p[nl].a,-1);
	}
	for(register int i=1;i<=Q;i++) printf("%d\n",res[i]?res[i]:-1);
}
发布了858 篇原创文章 · 获赞 106 · 访问量 7万+
展开阅读全文

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

©️2019 CSDN 皮肤主题: 程序猿惹谁了 设计师: 上身试试

分享到微信朋友圈

×

扫一扫,手机浏览