zoukankan      html  css  js  c++  java
  • 差分 离散化 (线段树优化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
    ",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));
        }
    }
  • 相关阅读:
    函数指针Demo
    设计模式笔记
    Simple Factory 模式
    百度API操作实例
    如何发邮件不被认定为垃圾邮件的技巧
    DateTimePicker中自定义时间或日期显示格式
    取得指定月份的天数
    DataGridView中的内容太长时换行显示
    Numericupdown控件value值的非空判断
    C#中用SQL语句CreatTable
  • 原文地址:https://www.cnblogs.com/qingjiuling/p/11274627.html
Copyright © 2011-2022 走看看