差分 离散化 (线段树优化lazy标记)2018ICPC SouthEastern Fishermen

题目链接: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\n",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\n",query(1,1,m,a[i].id));
    }
}

 

posted @ 2019-07-31 10:28  清酒令  阅读(290)  评论(0编辑  收藏  举报