PTA刷题

L3-017 森森快递 (30 分)

做法:

观察可以发现,当我们将这些区间按y排序,再按x排序以后,先取左边的一定比先取右边的更优,会影响的有以下情况:

1.区间重合

这样的话,其实先取长的会更优,这样的话,会把前面没取到的部分也取到,但是其实先取短的也再取长的也并不影响,

2.区间交叉

这种各取各的就好,先取左边的并不会使答案更差,设左边为a,右边为b,交叉为c,那么答案就是min(a+b,c),所以先取左边并不会更差

3.区间包含

这样的应当是取中间短的部分更优,

这道题发现一个坑点,在使用宏定义Min时千万不要存在递归,不然复杂度会成指数型增长,define宏定义因为不会真正调用函数的特性在一定情况下确实能增加速度,然而如果min与max的define宏定义函数的“实参”(其实它并不能叫做实参)中出现了一个复杂的计算的话,它会进行两次计算,这大大拖慢了程序的速度。所以我建议如果在使用define宏定义函数时,如果传值中出现了一个会进行时间较长的计算的函数的话,应该这样使用:

int t=calc();  //假如calc()是一个需要经过大量计算的函数
ans=min(t,ans);

所以线段树维护一下就好

#include <bits/stdc++.h>
using namespace std;

#define Min(a,b) ((a)<(b)?(a):(b))
typedef long long ll;
const int maxn=1e5+10;

class my{
    public:
        int x,y;
        my(int _x=0,int _y=0){
            x=_x;
            y=_y;
        }

        bool operator < (const my &rhs)const{
            if(y==rhs.y) return x<rhs.x;
            return y<rhs.y;
        }
}a[maxn];

ll tree[maxn*10],add[maxn*10];
int num=0;

inline void pushup(int rt){
    tree[rt]=Min(tree[rt<<1],tree[rt<<1|1]);
}

void build(int l,int r,int rt){
    if(l==r){
        scanf("%lld",&tree[rt]);
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}

void pushdown(int rt){
    if(add[rt]){
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        tree[rt<<1]+=add[rt];
        tree[rt<<1|1]+=add[rt];
        add[rt]=0;
    }
}

void change(int l,int r,int rt,int L,int R,ll k){
    if(l>=L && r<=R){
        add[rt]+=k;
        tree[rt]+=k;
        return ;
    }
    int mid=(l+r)>>1;
    pushdown(rt);
    if(L<=mid) change(l,mid,rt<<1,L,R,k);
    if(R>mid) change(mid+1,r,rt<<1|1,L,R,k);
    pushup(rt);
}

ll getans(int l,int r,int rt,int L,int R){
    if(l>=L && r<=R){
        return tree[rt];
    }
    int mid=(l+r)>>1;
    pushdown(rt);
    ll ans=1e18;
    if(L<=mid) {ll t=getans(l,mid,rt<<1,L,R);ans=Min(ans,t);}
    if(R>mid) {ll t=getans(mid+1,r,rt<<1|1,L,R);ans=Min(ans,t);}
    return ans;
}

int main(){
    #ifdef lmj_debug
        freopen("1.in","r",stdin);
    #endif
    int n,q;
    cin>>n>>q;
    n--;
    build(1,n,1);

    for (int i=1;i<=q;i++) {scanf("%d%d",&a[i].x,&a[i].y);if(a[i].x>a[i].y) swap(a[i].x,a[i].y);}
    ll ans=0;
    sort(a+1,a+1+q);
    for (int i=1;i<=q;i++){
        ll t=getans(1,n,1,a[i].x+1,a[i].y);
        ans+=t;
        change(1,n,1,a[i].x+1,a[i].y,-t);
    }

    printf("%lld\n",ans);
    return 0;
}
posted @ 2022-03-21 22:00  lmj_1  阅读(33)  评论(0)    收藏  举报