JZOJ3854. 【NOIP2014八校聯考第2場第2試9.28】分組(group) (Standard IO)

Description
Bsny所在的精靈社區有n個居民,每個居民有一定的地位和年齡,ri表示第i個人的地位,ai表示第i個人的年齡。
最近社區裏要舉行活動,要求幾個人分成一個小組,小組中必須要有一個隊長,要成爲隊長有這樣的條件:
1、隊長在小組中的地位應該是最高的(可以並列第一);
2、小組中其他成員的年齡和隊長的年齡差距不能超過K。
有些人想和自己親密的人組在同一個小組,同時希望所在的小組人越多越好。比如x和y想在同一個小組,同時希望它們所在的小組人越多越好,當然,它們也必須選一個符合上述要求的隊長,那麼問你,要同時包含x和y的小組,最多可以組多少人?
Input
第一行兩個整數n和K;
接下來一行輸入n個整數:r1, r2, …, rn
接下來一行輸入n個整數:a1, a2, …, an
接下來輸入Q表示有Q個詢問;
接下來Q行每行輸入x, y,表示詢問:當x和y組在同一個小組,它們小組最多可以有多少人(x和y也有可能被選爲隊長,只要它們符合條件)。
Output
對於每個詢問,輸出相應的答案,每個答案佔一行。
當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
【樣例解釋】
詢問1:當第5個人和第3個人想在一組時,小組成員可以有{1, 3, 4, 5},選擇3當隊長,而2不可以加入,因爲2加入的話,5和2的年齡差距爲2,超過K=1了;
詢問2:當第2個人和第3個人想在一組時,可以選擇{1, 2, 3};
詢問3:當2和5想在一起時,無法滿足要求;
詢問4:當4和1想在一起時,可以選擇{1, 3, 4, 5};
Data Constraint
20%的數據:2≤n≤100,0≤ k≤100,1≤ ri, ai ≤100,1≤ q≤ 100;
40%的數據:2≤ n≤1000,0≤ k≤ 1000,1≤ ri, ai ≤ 1000,1≤ q≤ 1000;
60%的數據:2≤ n≤ 10^4,0≤ k≤ 10^9,1≤ ri, ai ≤ 10^9, 1≤ q≤ 10^4;
100%的數據:2≤ n≤ 10^5,0≤ k≤ 10^9,1≤ ri, ai ≤ 10^9,1≤ q≤ 10^5,1≤ x, y≤ n, x≠y。

這道題想法挺妙的。
首先,對於每個隊長,我們要算出他當隊長時能夠率領的人個數Cap[k](包括他自己)
自然先把“地位”與“年齡“”按地位從小到大排序
然後用權值線段樹直接算即可(注意地位相同情況)
然後,如何算答案呢?
考慮將詢問按照Max(x的地位,y的地位)排序,離線處理
因爲爲了將x,y放入同一個組中,隊長地位必須大於等於Max(x的地位,y的地位)
把“地位”與“年齡“”按地位從大到小排序
將Cap依次扔入權值線段樹中。
查詢對應的年齡範圍中最大的Cap即可。

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int i,j,k,m,n,o,p,l,s,t,c,cnt,times,left,right,root;
struct node{
	int sta,age,id;
}a[200005],cc[200005];
struct wyd{
	int id,ans,x,y,px;
}b[200005];
struct WYD{
	int l,r,max,sum;
}tree[2500005];
int bz[200005],cap[200005];
int cmp1(node a,node b) {return a.sta<b.sta;}
int cmp2(node a,node b) {return a.id<b.id;}
int cmp3(wyd a,wyd b) {return a.px>b.px;}
int cmp4(wyd a,wyd b) {return a.id<b.id;}
void add_sum(int &x,int l,int r,int pos,int ad)
{
	if (!x) x=++cnt; 
	if (l==r) {
		tree[x].sum+=ad;return;
	}
	int mid=(l+r)>>1;
	if (pos<=mid) add_sum(tree[x].l,l,mid,pos,ad);
	else add_sum(tree[x].r,mid+1,r,pos,ad);
	tree[x].sum=tree[tree[x].l].sum+tree[tree[x].r].sum;
}
int query_sum(int x,int l,int r,int st,int en)
{
	if (l>=st&&r<=en) return tree[x].sum;
	int mid=(l+r)>>1;
	if (en<=mid) return query_sum(tree[x].l,l,mid,st,en);
	else if (st>mid) return query_sum(tree[x].r,mid+1,r,st,en);
	else return query_sum(tree[x].l,l,mid,st,mid)+query_sum(tree[x].r,mid+1,r,mid+1,en);
}
void add_max(int &x,int l,int r,int pos,int ad)
{
	if (!x) x=++cnt;
	if (l==r) {
		tree[x].max=max(tree[x].max,ad);return;
	}
	int mid=(l+r)>>1;
	if (pos<=mid) add_max(tree[x].l,l,mid,pos,ad);
	else add_max(tree[x].r,mid+1,r,pos,ad);
	tree[x].max=max(tree[tree[x].l].max,tree[tree[x].r].max);
}
int query_max(int x,int l,int r,int st,int en)
{
	if (l>=st&&r<=en) return tree[x].max;
	int mid=(l+r)>>1;
	if (en<=mid) return query_max(tree[x].l,l,mid,st,en);
	else if (st>mid) return query_max(tree[x].r,mid+1,r,st,en);
	else return max(query_max(tree[x].l,l,mid,st,mid),query_max(tree[x].r,mid+1,r,mid+1,en)); 
}
void read(int &x)
{
	x=0;char ch=getchar();
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=getchar();
}
int main()
{
	freopen("group.in","r",stdin);
	freopen("group.out","w",stdout);
	read(n),read(c);
	for (i=1;i<=n;i++) read(a[i].sta);
	for (i=1;i<=n;i++) read(a[i].age),a[i].id=i;
	sort(a+1,a+n+1,cmp1);cnt=1;
	memcpy(cc,a,sizeof(cc));root=1;
	for (i=1;i<=n;i++)
	{
		if (bz[i]) continue;
		bz[i]=1,add_sum(root,1,1e9,a[i].age,1);
		for (j=i+1;j<=n;j++)
			if (a[j].sta==a[j-1].sta) add_sum(root,1,1e9,a[j].age,1),bz[j]=1;
			else break;
		for (k=i;k<j;k++) cap[k]=query_sum(root,1,1e9,max(1,a[k].age-c),min(1000000000,a[k].age+c));
	}
	sort(a+1,a+n+1,cmp2);
	read(times);
	for (i=1;i<=times;i++) read(b[i].x),read(b[i].y),b[i].px=max(a[b[i].x].sta,a[b[i].y].sta),b[i].id=i;
	sort(b+1,b+times+1,cmp3);
	memset(tree,0,sizeof(tree));cnt=1;root=1;j=n;
	for (i=1;i<=times;i++)
	{
		if (a[b[i].x].age>a[b[i].y].age) swap(b[i].x,b[i].y);
		left=max(1,a[b[i].y].age-c),right=min(1000000000,a[b[i].x].age+c);
		for (;j>=1;j--)
		{
			if (cc[j].sta>=b[i].px) add_max(root,1,1e9,cc[j].age,cap[j]);
			else break;	
		} 
		if (left>right) b[i].ans=0;
		else b[i].ans=query_max(root,1,1e9,left,right);
	}
	sort(b+1,b+times+1,cmp4);
	for (i=1;i<=times;i++) 
	{
		if (!b[i].ans) b[i].ans--;
		printf("%d\n",b[i].ans);
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章