HDU 4268 - Alice and Bob

来源:互联网 发布:淘宝客服基础知识 编辑:程序博客网 时间:2024/05/22 15:17

 

题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=4268

 

贪心 + 树状数组

 

贪心是怪叔叔想到的,然后让我敲~~  = =

 

一开始敲搓了,搓B不解释了~~ 

 

贪心的想法很简单:

 

          首先:A和B混合排序,先按照L排,L相等的按照W排,W相等的B排A前面。

 

          然后,从头到尾依次遍历,假若遍历到B,则将B的W作为下标加入到树状数组中(当然W需要离散化,而树状数组tree[W]表示B的W的个数)。。。

 

          假若遍历到A,那么就去 [1,A的W] 这个区间内找是否存在有B的W,如果有,则将最大的B的W删除,当作被A覆盖。。。

 

那么树状数组的用途?

 

每次以O(2logn)的时间找到 [1,A的W] 中,最接近A的W的那个B的W。。。

 

那么怎么找?  首先求和,也就是 [1,A的W] 这个区间内 B的W 的个数num。。。

 

这时,我们利用树状数组求第num大的方法,得到一个W,那么这个W就是 [1,A的W] 这个区间中最接近 A的W 的那个 B的W 。。。

 

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<queue>#include<map>#define ll (v<<1)#define rr (v<<1|1)#define mid ((l+r)>>1)using namespace std;struct Node{int l,w,i;}node[210000];int cmpL(Node a,Node b){return a.l!=b.l?a.l<b.l:(a.w==b.w?a.i<b.i:a.w<b.w);}int cmpW(Node a,Node b){return a.w<b.w;}int tol,n,nn;void INITW(){int i,tmp=1001010011;tol=0;for(i=0;i<nn;i++){if(node[i].w!=tmp){tmp=node[i].w;node[i].w=++tol;}else{node[i].w=tol;}}}int tree[210000];int lowbit(int x){return x&-x;}int fk(int k){  int i,now=0;for(i=20;i>=0;i--){now|=(1<<i);if(now>=tol || tree[now]>=k)now^=(1<<i);else k-=tree[now];}return now+1;}void add(int v,int val){while(v<=tol){tree[v]+=val;v+=v&-v;}}int query(int v){int sum=0;while(v>0){sum+=tree[v];v-=v&-v;}return sum;}int main(){int res,t,i,j,k,w;scanf("%d",&t);while(t--){scanf("%d",&n);nn=n+n;for(i=0;i<n;i++){scanf("%d%d",&node[i].l,&node[i].w);node[i].i=1;}for(i=n;i<nn;i++){scanf("%d%d",&node[i].l,&node[i].w);node[i].i=0;}sort(node,node+nn,cmpW);INITW(); // 先排序W,然后对其离散化sort(node,node+nn,cmpL);res=0;for(i=0;i<=tol;i++){tree[i]=0;}for(i=0;i<nn;i++){if(node[i].i==0){add(node[i].w,1);continue;}else{k=query(node[i].w);if(k==0){continue;}w=fk(k);add(w,-1);res++;}}printf("%d\n",res);}return 0;}


 

 

 

 

原创粉丝点击