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;
}