题目地址: 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;
}