推销员 (贪心线段树)

https://www.luogu.org/problemnew/show/P2672
题 意 很 简 单 , p a s s 题意很简单,pass pass
题解:题目说了:在不走多余路的前提下,求最大的疲劳值。不走多余路意思就是不能绕来绕去地走,也就是往前走到最远处后只能往回走,不能有两次以上的折返。因此可以直接贪心。

对于 x = 1 x=1 x=1的情况,答案肯定就是 2 ∗ s [ i ] + a [ i ] 2*s[i] +a[i] 2s[i]+a[i]中的最大值,更新一下这个最大值的下标id,表示能到达的最远点

对于 x > 1 x>1 x>1的情况,那么就分为两种:一种在最远点id的左侧,那么对答案的贡献是 a [ i ] a[i] a[i],另一种在id的右侧,对答案的贡献是$
2 ∗ s [ i ] − 2 ∗ s [ i d ] + a [ i ] 2*s[i]-2*s[id]+a[i] 2s[i]2s[id]+a[i]
我们只需要判断这两种贡献的大小,然后不断更新最远点的下标 i d id id 就ok了。

贪心思路想好后,对 a [ i ] a[i] a[i] 2 ∗ s [ i ] + a [ i ] 2*s[i]+a[i] 2s[i]+a[i]分别建树(t1,t2),用线段树维护区间最大值。
每选中一个点,如果这个点在最远点 i d id id的左侧,那么将t1线段树对应的点更新为0,对t2相同

#include
using namespace std;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef long long ll;
const int mx = 1e5+5;
struct node{
    ll val;
    int id;
    node(ll x = 0,int y = 0){val = x,id = y;}
    friend bool operator <(const node& a, const node& b){
        if(a.val != b.val) return a.val < b.val;
        return a.id > b.id;
    }
}t1[mx<<2],t2[mx<<2];
ll s[mx];
ll a[mx];
void pushup(int rt){
    t1[rt] = max(t1[rt<<1],t1[rt<<1|1]);
    t2[rt] = max(t2[rt<<1],t2[rt<<1|1]);
}
void build(int l,int r,int rt){
    if(l == r){
        t1[rt].val = a[l];
        t1[rt].id = l;
        t2[rt].val = 2ll*s[l]+a[l];
        t2[rt].id = l;
        return;
    }
    int mid = (l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update1(int l,int r,int rt,int pos){
    if(l == r){
        t1[rt] = node(0,0);
        return;
    }
    int mid = (l+r)>>1;
    if(pos <= mid) update1(lson,pos);
    else update1(rson,pos);
    pushup(rt);
}
void update2(int l,int r,int rt,int pos){
    if(l == r){
        t2[rt] = node(0,0);
        return;
    }
    int mid = (l+r)>>1;
    if(pos <= mid) update2(lson,pos);
    else update2(rson,pos);
    pushup(rt);
}
node query1(int l,int r,int rt,int L,int R){
	if(L > R) return node(0,0);
    if(L <= l && R >= r){
        return t1[rt];
    }
    int mid = (l+r)>>1;
    node xx(0,0);
    if(L <= mid) xx = max(xx,query1(lson,L,R));
    if(R > mid) xx = max(xx,query1(rson,L,R));
    return xx;
}
node query2(int l,int r,int rt,int L,int R){
	if(L > R) return node(0,0);
    if(L <= l && R >= r){
        return t2[rt];
    }
    int mid = (l+r)>>1;
    node xx(0,0);
    if(L <= mid) xx = max(xx,query2(lson,L,R));
    if(R > mid) xx = max(xx,query2(rson,L,R));
    return xx;
}
int n;

int main(){
    cin>>n;
    for(int i = 1; i <= n; i++){
        scanf("%lld",&s[i]);
    }
    for(int i = 1; i <= n; i++){
        scanf("%lld",&a[i]);
    }
    build(1,n,1);
    node ans1 = query1(1,n,1,1,n);
    node ans2 = query2(1,n,1,1,n);
    int id; ll ans = 0;
    if(ans1.val > ans2.val){
        ans = ans1.val;
        id = ans1.id;
    }else{
        ans = ans2.val;
        id = ans2.id;
    }
    update1(1,n,1,id);
    update2(1,n,1,id);
    printf("%lld\n",ans);
    for(int x = 2; x <= n; x++){
        ans1 = query1(1,n,1,1,id-1);
        ans2 = query2(1,n,1,id+1,n);
        ll tmp = ans2.val-2*s[id];
        /*printf("s1:%d %d\n",ans1.val,ans1.id);
    	printf("s2:%d %d\n",ans2.val,ans2.id);*/
        if(ans1.val > tmp){
            ans += ans1.val;
            update1(1,n,1,ans1.id);
            //update2(1,n,1,id);
        }else{
            ans += tmp;
            id = ans2.id;
            update2(1,n,1,id);
        }
        printf("%lld\n",ans);
    }
}

你可能感兴趣的:(线段树,贪心,线段树)