codeforces 173E 组队
2016-08-19 21:02
148 查看
Bsny所在的精灵社区有n个居民,每个居民有一定的地位和年龄,ri表示第i个人的地位,ai表示第i个人的年龄。
最近社区里要举行活动,要求几个人组成一个小组,小组中必须要有一个队长,要成为队长有这样的条件:
1. 队长在小组中的地位应该是最高的(可以并列第一),
2. 小组中其他成员的年龄和队长的年龄差距不能超过K
有些人想和自己亲密的人组在同一个小组,同时希望所在的小组人越多越好。比如x和y想在同一个小组,同时希望它们所在的小组人越多越好,当然,它们也必须选一个符合上述要求的队长,那么问你,要同时包含x和y的小组,最多可以组多少人?
输入
首先输入n和K
接下来一行输入n个整数: r1, r2, …, rn
接下来一行输入n个整数: a1, a2, …, an
接下来输入Q表示有Q个询问
接下来Q行每行输入x, y, 表示询问:当x和y组在同一个小组,它们小组最多可以有多少人(x和y也有可能被选为队长,只要它们符合条件)
输出
对于每个询问,输出相应的答案
每个答案占一行
当x和y无法在同一组时,输出-1(比如x的年龄是1, y的年龄是100,K=1,无论谁当队长,x和y两者中,总会有人跟队长的年龄差距超过K,那么输出-1)
样例输入
5 1
1 5 4 1 2
4 4 3 2 2
4
5 3
2 3
2 5
4 1
样例输出
4
3
-1
4
提示
样例解释:
询问1:当第5个人和第3个人想在一组时,小组成员可以有{1, 3, 4, 5},选择3当队长,而2不可以加入,因为2加入的话,5和2的年龄差距为2,超过K=1了。所以答案为4
询问2:当第2个人和第3个人想在一组时,可以选择{1, 2, 3}
询问3:当2和5想在一起时,无法满足要求
询问4:当4和1想在一起时,可以选择{1, 3, 4, 5}
数据范围:
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<=104, 0<=K<=109, 1<=ri, ai <=109, 1<=q<=104
100%的数据 :
2<=n<=105, 0<=K<=109, 1<=ri, ai <=109, 1<=q<=105
1<=x, y<=n, x!=y
离散化+树状数组+离线处理+线段树
首先对于每个人,我们可以预处理如果他是队长的话,最多可以有少人组队:
这里需要对r进行从小到大排序,排序完后,我们可以从小到大遍历每个人,利用树状数组统计[ai−k,ai+k]的人数,即为第i个人作为队长最大组队人数
这里要对相同r的时候特殊处理一下
然后,对于一组询问x,y, 我们可以计算出能包含x,y的组,队长的a和r的限制条件,即a的范围为[max(x.a−k,y.a+k),min(x.a+k,y.a+k)], r的范围为r>=max(x.r,y.r)
我们可以在符合a,r范围的所有人中寻找最大值
但考虑到询问比较大,我们可以采取离线的方式处理询问:
用rmin表示满足询问r的最小值,即max(x.r, y.r),对询问根据rmin从大到小排序,接下来的处理就是求[max(x.a-k, y.a+k), min(x.a+k, y.a+k)]范围中最大值是多少,这个可以用线段树来维护和求解
如果max(x.a-k, y.a+k)> min(x.a+k, y.a+k)或者找不到符合r的人,那么答案为-1
因此,总的复杂度为O(nlogn)
后记:写了一个半钟头,各种下标和二分真是头疼。。。不过总算对离线有更深刻的认识了:如果在线有两个条件,难以一起解决的话,那么就离线,对其中某个条件进行排序,不用再管它,然后就可以转化为区间问题了。
最近社区里要举行活动,要求几个人组成一个小组,小组中必须要有一个队长,要成为队长有这样的条件:
1. 队长在小组中的地位应该是最高的(可以并列第一),
2. 小组中其他成员的年龄和队长的年龄差距不能超过K
有些人想和自己亲密的人组在同一个小组,同时希望所在的小组人越多越好。比如x和y想在同一个小组,同时希望它们所在的小组人越多越好,当然,它们也必须选一个符合上述要求的队长,那么问你,要同时包含x和y的小组,最多可以组多少人?
输入
首先输入n和K
接下来一行输入n个整数: r1, r2, …, rn
接下来一行输入n个整数: a1, a2, …, an
接下来输入Q表示有Q个询问
接下来Q行每行输入x, y, 表示询问:当x和y组在同一个小组,它们小组最多可以有多少人(x和y也有可能被选为队长,只要它们符合条件)
输出
对于每个询问,输出相应的答案
每个答案占一行
当x和y无法在同一组时,输出-1(比如x的年龄是1, y的年龄是100,K=1,无论谁当队长,x和y两者中,总会有人跟队长的年龄差距超过K,那么输出-1)
样例输入
5 1
1 5 4 1 2
4 4 3 2 2
4
5 3
2 3
2 5
4 1
样例输出
4
3
-1
4
提示
样例解释:
询问1:当第5个人和第3个人想在一组时,小组成员可以有{1, 3, 4, 5},选择3当队长,而2不可以加入,因为2加入的话,5和2的年龄差距为2,超过K=1了。所以答案为4
询问2:当第2个人和第3个人想在一组时,可以选择{1, 2, 3}
询问3:当2和5想在一起时,无法满足要求
询问4:当4和1想在一起时,可以选择{1, 3, 4, 5}
数据范围:
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<=104, 0<=K<=109, 1<=ri, ai <=109, 1<=q<=104
100%的数据 :
2<=n<=105, 0<=K<=109, 1<=ri, ai <=109, 1<=q<=105
1<=x, y<=n, x!=y
离散化+树状数组+离线处理+线段树
首先对于每个人,我们可以预处理如果他是队长的话,最多可以有少人组队:
这里需要对r进行从小到大排序,排序完后,我们可以从小到大遍历每个人,利用树状数组统计[ai−k,ai+k]的人数,即为第i个人作为队长最大组队人数
这里要对相同r的时候特殊处理一下
然后,对于一组询问x,y, 我们可以计算出能包含x,y的组,队长的a和r的限制条件,即a的范围为[max(x.a−k,y.a+k),min(x.a+k,y.a+k)], r的范围为r>=max(x.r,y.r)
我们可以在符合a,r范围的所有人中寻找最大值
但考虑到询问比较大,我们可以采取离线的方式处理询问:
用rmin表示满足询问r的最小值,即max(x.r, y.r),对询问根据rmin从大到小排序,接下来的处理就是求[max(x.a-k, y.a+k), min(x.a+k, y.a+k)]范围中最大值是多少,这个可以用线段树来维护和求解
如果max(x.a-k, y.a+k)> min(x.a+k, y.a+k)或者找不到符合r的人,那么答案为-1
因此,总的复杂度为O(nlogn)
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define p1 id<<1 #define p2 id<<1^1 using namespace std; int n,m,cas,x,y,old; struct ty { int fame,age,id,v; }p[100005],a[100005]; struct node { int x,y,z,id; }q[100005]; int c[100005],d[100005],tree[400005]; int pos[100005],age[100005],ans[100005]; void add(int k,int delta) { while(k<=old) { c[k]=c[k]+delta; k=k+(k&-k); } } int sum(int k) { int res=0; while(k>0) { res=res+c[k]; k=k-(k&-k); } return res; } void update(int id,int l,int r,int x,int y) { if(l==r) { tree[id]=max(tree[id],y); return; } int mid=(l+r)/2; if(x<=mid) update(p1,l,mid,x,y); else update(p2,mid+1,r,x,y); tree[id]=max(tree[p1],tree[p2]); } int query(int id,int l,int r,int x,int y) { if(x<=l&&r<=y) return tree[id]; int mid=(l+r)/2; if(y<=mid) return query(p1,l,mid,x,y); else if(x>mid) return query(p2,mid+1,r,x,y); else return max(query(p1,l,mid,x,mid),query(p2,mid+1,r,mid+1,y)); } bool cmp(ty x,ty y) { return x.age<y.age; } bool haha(ty x,ty y) { return x.fame<y.fame; } bool CMP(node a,node b) { return a.z>b.z; } int erfen(int l,int r,int x) { if(l>r) return a[l].v; int mid=(l+r)/2; if(x>a[mid].age) return erfen(mid+1,r,x); else return erfen(l,mid-1,x); } int ERFEN(int l,int r,int x) { if(l>r) return a[r].v; int mid=(l+r)/2; if(x>=a[mid].age) return ERFEN(mid+1,r,x); else return ERFEN(l,mid-1,x); } void prepare() { cin>>n>>m; for(int i=1;i<=n;i++) { scanf("%d",&p[i].fame); pos[i]=p[i].fame; } for(int i=1;i<=n;i++) { scanf("%d",&p[i].age); age[i]=p[i].age; a[i].age=p[i].age; p[i].id=a[i].id=i; } sort(a+1,a+n+1,cmp); old=0; for(int i=1;i<=n;i++) { if(a[i].age!=a[i-1].age) old++; p[a[i].id].v=old; a[i].v=old; } sort(p+1,p+n+1,haha); int pre=1; for(int i=1;i<=n;i++) { if(p[i].fame!=p[i-1].fame) { for(int j=pre;j<i;j++) { int down=max(1,erfen(1,n,p[j].age-m)); int up=min(old,ERFEN(1,n,p[j].age+m)); d[p[j].id]=sum(up)-sum(down-1); } pre=i; } add(p[i].v,1); } for(int i=pre;i<=n;i++) { int down=max(1,erfen(1,n,p[i].age-m)); int up=min(old,ERFEN(1,n,p[i].age+m)); d[p[i].id]=sum(up)-sum(down-1); } } void solve() { cin>>cas; for(int i=1;i<=cas;i++) { scanf("%d%d",&q[i].x,&q[i].y); q[i].z=max(pos[q[i].x],pos[q[i].y]); q[i].id=i; } sort(q+1,q+cas+1,CMP); int w=n; for(int i=1;i<=cas;i++) { while(p[w].fame>=q[i].z) { update(1,1,old,p[w].v,d[p[w].id]); w--; } x=q[i].x; y=q[i].y; int down=max(1,erfen(1,n,max(age[x]-m,age[y]-m))); int up=min(old,ERFEN(1,n,min(age[x]+m,age[y]+m))); if(down<=up) ans[q[i].id]=query(1,1,old,down,up); } for(int i=1;i<=cas;i++) if(ans[i]==0) printf("-1\n"); else printf("%d\n",ans[i]); } int main() { prepare(); solve(); return 0; }
后记:写了一个半钟头,各种下标和二分真是头疼。。。不过总算对离线有更深刻的认识了:如果在线有两个条件,难以一起解决的话,那么就离线,对其中某个条件进行排序,不用再管它,然后就可以转化为区间问题了。
相关文章推荐
- codeforces 173E 组队 线段树+离线
- codeforces 173E 数据结构 好题
- 第十周周赛——周赛兼组队赛第二场题解(出自 BNUOJ28207,BNUOJ28201,BNUOJ28209,codeforces 667B,HDU 5439,HDU 5478)
- CodeForces 173E
- 第九周周赛——周赛兼组队赛第一场题解(出自HDU5443,本oj,HDU 5667,poj1742,codeforces 664A,BUNOJ 28199)
- C. Table Decorations(Codeforces)(规律)
- CodeForces 611D New Year and Ancient Prophecy
- Codeforces 615A Bulbs 【水题】
- 基础题 CodeForces - 631B Print Check
- Codeforces 520A - Pangram
- CodeForces 896D Nephren Runs a Cinema(组合计数+数论+数形结合)
- CodeForces 361B
- CodeForces 471C MUH and House of Cards
- 【Codeforces】-611A-New Year and Days(水)
- codeforces 755D. PolandBall and Polygon
- 【Codeforces 831 C. Jury Marks】+ STL
- Theatre Square_Codeforces_1A
- codeforces 468B 2-sat
- hdoj 4288 && Codeforces 85D Coder 【线段树】
- codeforces 698B fix a tree 时间戳