BZOJ 3022 [Balkan2012]The Best Teams(扫描线+线段树)
2017-07-29 22:12
501 查看
【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=3022
【题目大意】
给定n个球员,第i个球员年龄为AGEi,水平为SKILLi。
没有任何两个球员的水平相同。将这些球员按水平排序,
对于一次比赛,你需要选择若干个球员去比赛,但不能同时选择两个水平相邻的球员。
m次询问,每次给定a和k,表示要在年龄不超过a的球员中选择不超过k个球员,
请计算skill和的最大值。
【题解】
对于询问年龄的限制,我们可以通过扫描线来处理。
我们将所有人的水平映射到线段上,随着线扫描在相应的位置更新上水平,
那么问题就转化为在权值线段树上求解k个不相邻的位置,使得权值和最大,
我们维护g[0/1]数组表示r+1不选/选的时候,l位置选不选
c[0/1]数组表示r+1不选/选的时候,中间选了几个。
s[0/1]数组表示r+1不选/选的时候,中间选的和。
查询则类似权值线段树上的k大数查询。
学习了一下Claris的非递归线段树写法。
【代码】
【题目大意】
给定n个球员,第i个球员年龄为AGEi,水平为SKILLi。
没有任何两个球员的水平相同。将这些球员按水平排序,
对于一次比赛,你需要选择若干个球员去比赛,但不能同时选择两个水平相邻的球员。
m次询问,每次给定a和k,表示要在年龄不超过a的球员中选择不超过k个球员,
请计算skill和的最大值。
【题解】
对于询问年龄的限制,我们可以通过扫描线来处理。
我们将所有人的水平映射到线段上,随着线扫描在相应的位置更新上水平,
那么问题就转化为在权值线段树上求解k个不相邻的位置,使得权值和最大,
我们维护g[0/1]数组表示r+1不选/选的时候,l位置选不选
c[0/1]数组表示r+1不选/选的时候,中间选了几个。
s[0/1]数组表示r+1不选/选的时候,中间选的和。
查询则类似权值线段树上的k大数查询。
学习了一下Claris的非递归线段树写法。
【代码】
#include <cstdio> #include <algorithm> using namespace std; typedef long long LL; const int N=300010,M=N<<2; int n,m,disc ; LL ans ; struct E{int x,y,id;}a ,b ; bool cmp(E a,E b){return a.x<b.x;} namespace Segment_Tree{ int pos ; struct data{bool g[2];int c[2];LL s[2];}T[M]; void build(int x,int l,int r){ if(l==r){pos[l]=x;return;} int mid=(l+r)>>1; build(x<<1,l,mid);build(x<<1|1,mid+1,r); } void change(int x,int y){ x=pos[x]; T[x].g[0]=T[x].c[0]=1,T[x].s[0]=y; for(x>>=1;x;x>>=1)for(int i=0;i<2;i++){ bool j=T[x<<1|1].g[i]; T[x].g[i]=T[x<<1].g[j]; T[x].c[i]=T[x<<1].c[j]+T[x<<1|1].c[i]; T[x].s[i]=T[x<<1].s[j]+T[x<<1|1].s[i]; } } LL ask(int k){ int x=1,l=1,r=n,u=0; LL res=0; while(k){ if(k>=T[x].c[u]){res+=T[x].s[u];break;} if(l==r)break; int mid=(l+r)>>1; x=x<<1|1; if(k<=T[x].c[u])l=mid+1; else{ k-=T[x].c[u]; res+=T[x].s[u]; u=T[x].g[u]; r=mid; x--; } }return res; } } int remark(int x){ int l=1,r=n; while(l<=r){ int mid=(l+r)>>1; if(disc[mid]<x)l=mid+1; else if(disc[mid]==x)return mid; else r=mid-1; } } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y),disc[i]=a[i].y; scanf("%d",&m); for(int i=1;i<=m;i++)scanf("%d%d",&b[i].x,&b[i].y),b[i].id=i; sort(a+1,a+n+1,cmp); sort(b+1,b+m+1,cmp); sort(disc+1,disc+n+1); Segment_Tree::build(1,1,n); for(int i=1,j=1;i<=m;i++){ while(j<=n&&a[j].x<=b[i].x)Segment_Tree::change(remark(a[j].y),a[j].y),j++; ans[b[i].id]=Segment_Tree::ask(b[i].y); }for(int i=1;i<=m;i++)printf("%lld\n",ans[i]); return 0; }
相关文章推荐
- BZOJ3022 : [Balkan2012]The Best Teams
- [BZOJ4059][Cerc2012]Non-boring sequences(扫描线+线段树||暴力分治)
- BZOJ 2584: [Wc2012]memory(扫描线+线段树)
- BZOJ 2752: [HAOI2012]高速公路(road)( 线段树 )
- [BZOJ 2809][Apio2012]dispatching:可持久化线段树|可并堆
- bzoj 2811: [Apio2012]Guard【线段树+贪心】
- bzoj 2733: [HNOI2012]永无乡(线段树启发式合并)
- [BZOJ1218][HNOI2003]激光炸弹(扫描线+线段树)
- bzoj 2658: [Zjoi2012]小蓝的好友(mrx) treap+扫描线
- BZOJ3019 : [Balkan2012]handsome
- BZOJ 2733 [HNOI2012]永无乡 可持久化线段树合并
- bzoj 2733: [HNOI2012]永无乡 (线段树合并)[省选计划系列]
- [BZOJ1818][Cqoi2010]内部白点(扫描线+线段树)
- [删边最短路 并查集||线段树] BZOJ 2725 [Violet 6]故乡的梦 & 4400 tjoi2012 桥
- BZOJ 4059 Cerc2012 Non-boring sequences 线段树+扫描线
- [BZOJ1645][Usaco2007 Open]City Horizon 城市地平线(扫描线+线段树)
- bzoj 2752: [HAOI2012]高速公路(road) 线段树
- [BZOJ 2731][HNOI 2012]三角形覆盖问题(计算几何+扫描线暴力)
- bzoj 2752: [HAOI2012]高速公路(road) (线段树)
- bzoj 2733: [HNOI2012]永无乡 -- 线段树