题目链接:https://nanti.jisuanke.com/t/40367
题意:有n条鱼和m个渔夫,渔夫全在海岸线上,鱼竿长l,设a,b是鱼的横纵坐标,x是渔夫的坐标(y全为0),二者的距离是|a-x|+b,求问每个渔夫能吊到多少鱼
有两种做法,分别是差分和线段树
差分做法:我们知道,差分是利用元数据之间的联系,逻辑关系来求元数据的,这个题非常符合差分的思想,鱼每次改变的都是一个区间整体改变,而我们不需要求这个区间的和,而只需要求每个端点的数据,这样直接修改差分数组两端就可以了,最后求元数据时从头到尾一步步来就好。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=1e9+7; const int maxn=2e5+7; const ll inf=1e18+7; const double pi=acos(-1); struct node{ ll x,y; }a[maxn]; struct node2{ int id,idd;//因为是离线做的,最后需要输出,id记录了原先是第几个渔夫,idd则记录了是第几个结点 ll x; bool operator <(const node2 & a) const{ return x<a.x; } }b[maxn]; int diff[maxn];//差分数组 int ans[maxn]; //记录答案的数组 int main(){ int n,m;ll l;scanf("%d%d%lld",&n,&m,&l); for(int i=1;i<=n;i++)scanf("%d%d",&a[i].x,&a[i].y); for(int i=1;i<=m;i++){ scanf("%d",&b[i].x); b[i].id=i; } sort(b+1,b+1+m); for(int i=1;i<=m;i++) b[i].idd=i; for(int i=1;i<=n;i++){ if(a[i].y>l) continue;//注意,不等式左边大于右边属于无效,需要舍去 node2 tmp; tmp.x=a[i].x+a[i].y-l; int xx=lower_bound(b+1,b+m+1,tmp)-b; tmp.x=a[i].x+l-a[i].y; int yy=upper_bound(b+1,b+m+1,tmp)-b; diff[xx]++;diff[yy]--;//求出的xx,yy分别是鱼满足区间的左端点(离散化后)和右端点+1,故一个加,一个减 } for(int i=1;i<=m;i++){ diff[i]+=diff[i-1]; ans[b[i].id]=diff[b[i].idd]; } for (int i=1;i<=m;i++) printf("%d ",ans[i]); return 0; }
线段树做法:
线段树做法比较直白,对每个鱼直接修改区间,区间上每个数都加一,但正如前面所说,我们不需要维和区间和,只需要知道每个结点值即可,可以用简化的lazy标记,并且维护的区间是1-m,这点很容易错,写法很好,多看看。
#include<iostream> #include<cstdio> #include<algorithm> #define mid (l+r)/2 using namespace std; typedef long long ll; const int maxn=2e5+10; ll dat[4*maxn],add[4*maxn]; struct xx{ ll x,y; }fish[maxn]; struct pop{ ll id,v; friend bool operator < (pop x,pop y){ if(x.v==y.v) return x.id<y.id; return x.v<y.v; } }a[maxn],b[maxn]; ll c[maxn]; void update(ll a,ll l,ll r,ll s,ll t,ll k){ if(s<=l && r<=t){ dat[a]+=k; return; } if(dat[a]!=0) dat[2*a]+=dat[a],dat[2*a+1]+=dat[a],dat[a]=0; if(s<=mid) update(a<<1,l,mid,s,t,k); if(t>mid) update(a<<1|1,mid+1,r,s,t,k); } ll query(ll a,ll l,ll r,ll p){ if(l==r){ return dat[a]; } if(dat[a]!=0) dat[2*a]+=dat[a],dat[2*a+1]+=dat[a],dat[a]=0; if(p<=mid) return query(a<<1,l,mid,p); else return query(a<<1|1,mid+1,r,p); } int main(){ ll n,m,LL; scanf("%lld%lld%lld",&n,&m,&LL); for(int i=1;i<=n;i++){ scanf("%lld%lld",&fish[i].x,&fish[i].y); } for(int i=1;i<=m;i++){ scanf("%lld",&a[i].v); b[i].v=a[i].v; b[i].id=i; } sort(b+1,b+1+m); for(int i=1;i<=m;i++) a[b[i].id].id=i,c[i]=b[i].v; for(int i=1;i<=n;i++){ ll x0=LL-fish[i].y; if(x0<0) continue; ll l=max(fish[i].x-x0,1ll),r=fish[i].x+x0; int L,R; L=lower_bound(c+1,c+1+m,l)-c; R=upper_bound(c+1,c+1+m,r)-c-1; if(R<L)continue; update(1,1,m,L,R,1); } for(int i=1;i<=m;i++){ printf("%lld ",query(1,1,m,a[i].id)); } }