题解 P3088 【[USACO13NOV]Crowded Cows S】
作为最优解我来发个题解
单调队列不是O(n)的吗?加上排序应该也很快啊
但是线段树也不慢,像我就轻轻松松拿了个rk1
不过楼顶那篇题解跑的好快啊,62ms又破了我纪录
闲话少叙,进入正题
线段树作为最优的一种可以动态的访问区间最值的数据结构,比树状数组更快,比Spare Table使用更广泛(带修),比单调队列更具有随机访问性质,不需要滑动窗口这样询问有一定规律。
线段树绝对是最强力的数据结构,权值线段树可以吊打平衡树,函数式线段树/可持久化线段树可以碾压树状数组套平衡树(少至少一个log),极端的,替罪羊树套权值线段树可以爆锤块状链表套权值块状数组(
此题的数据规模较大,暴力肯定死翘翘,卡过去的是神仙。
x(i)太大,又不好离散化,我们考虑用lower_bound/
upper_bound来定位区间端点。
不过要先排个序,把节点简单用数组下标离散一下,把线段树的位置定好,然后单点修改或整体建树。
查询i时找h[i]-D~h[i]+D区间,二分一下即可。
找到区间后找一个最大值S(线段树维护)。
如果S>=h[i]*2,则ans++。
最后输出ans。
喜闻乐见的代码。
很多地方是可以优化的(我太懒了不想再优化),大家试试能不能卡卡常破纪录。
#include <cstdio>
#include <algorithm>
using namespace std;
void read(int &x){
char c=getchar();
int k=1;
while(c<'0'||c>'9') {if(c=='-') k=-1;c=getchar();}
for(x=0;c>='0'&&c<='9';c=getchar())
x=x*10+c-'0';
x*=k;
}
const int N=200005;
int n,p,q,m,k,y,x,s,ans,c,mx,d,b[N];
struct fox{
int wei,high;
}a[N*4];
bool operator<(fox x,fox y){
return x.wei<y.wei;
}
int tree[N];
inline void change(int k,int l,int r,int x,int y){
if(l>x||r<x) return;
if(l==x&&l==r){
tree[k]=y;
return;
}
int mid=l+r>>1;
change(k<<1,l,mid,x,y);
change(k<<1|1,mid+1,r,x,y);
tree[k]=max(tree[k<<1],tree[k<<1|1]);
}
inline int query(int k,int l,int r,int x,int y){
if(l>r) return 0;
if(l>y||r<x) return 0;
if(x<=l&&r<=y) return tree[k];
int mid=l+r>>1,s=query(k<<1,l,mid,x,y);
s=max(query(k<<1|1,mid+1,r,x,y),s);
return s;
}
int main(){
read(n);read(m);
for(register int i=1;i<=n;i++){
read(a[i].wei);read(a[i].high);
}
sort(a+1,a+n+1);
for(register int i=1;i<=n;++i){
change(1,1,n,i,a[i].high);
b[i]=a[i].wei;
}
for(register int i=1;i<=n;i++){
p=q=b[i];
p-=m;p=max(p,0);
q+=m;
k=lower_bound(b+1,b+n+1,p)-b;
c=upper_bound(b+1,b+n+1,q)-b-1;//-1很重要
s=query(1,1,n,k,i);d=query(1,1,n,i,c);
if(min(s,d)>=a[i].high*2){
ans++;
}
}
printf("%d",ans);
return 0;
}