Trip to Saint Petersburg CodeForces-1250 C

题解:
我们首先枚举每个日期i,对于每个日期,对[1,i]区间内的值减去k,代表新增加了一天花费值
如果有了收入我们就把区间[第一天开始,这个工作开始得日子]加上val。
举个栗子:
在这里插入图片描述
首先:
看这张图,我们先假设他没有活干,那么假设经过了6天,每天花费对应的值为上图,
1.如果你在第一天去了那个地方,那么到了第六天,对应得花费就是数字1下面对应得数字
2.如果你在第二天去了那个地方,那么到了第六天,对应得花费就是数字2下面对应得数字
……
6.如果你在第六天去了那个地方,那么到了第六天,对应得花费就是数字6下面对应得数字
这样大概就明白了线段树储是如何储存得了。

在这里插入图片描述
其次:
如果我们在第4-6天有一份兼职工作,每天转val元,那么我们把这个工作加在区间[1,4]上,如图所示。
1.如果你在第一天去了那个地方,那么到了第六天,对应得花费就是数字1下面对应得数字
2.如果你在第二天去了那个地方,那么到了第六天,对应得花费就是数字2下面对应得数字
……
6.如果你在第四天去了那个地方,那么到了第六天,对应得花费就是数字4下面对应得数字

这里你可能会思考一个问题,如果工作时间再第七天结束怎么办,其实不必考虑这个问题,因为我们是按照每份工作得结束时间进行枚举得,既然他能加到线段树上去,那么结束时间必定是在这个日期之前结束得。

这个地方需要细品,理解了就会做了

其实这个题可以理解为区间最值查询,并且需要输出最值相对应的区间,所以线段树也要维护一下区间范围。

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 2e5+10;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef long long ll;
const int mod = 100000000;
using namespace std;
struct wazxy{
    ll l,val,id;
    wazxy(ll x,ll y,ll z){l=x,val=y,id=z;}
};
vector<wazxy> v[maxn];
ll add[maxn<<2];
ll imax[maxn<<2];
ll section[maxn<<2];
void Add(int node,ll val){
    add[node]+=val;
    imax[node]+=val;
    return ;
}
void push_down(int node){  //这个跟上面的Add函数都是线段树的lazy操作
    if(!add[node]) return;
    Add(node*2,add[node]);   //pushdown
    Add(node*2+1,add[node]);
    add[node]=0;
}
void build(int node,int start,int ends){  //新键线段树,这里新建的目的是要维护左端点值
    if(start==ends){
        section[node]=start;   //更新区间左端的值
        return;
    }
    int mid=(start+ends)/2;
    build(node*2,start,mid);
    build(node*2+1,mid+1,ends);
}

void update(int node,int start,int ends,int l,int r,ll val){  //更新区间操作
    if(start>=l&&ends<=r){
        Add(node,val);
        return;
    }
    int mid=(start+ends)/2;
    push_down(node);
    if(l<=mid) update(node*2,start,mid,l,r,val);
    if(r>mid) update(node*2+1,mid+1,ends,l,r,val);
    //跟平时不同的是,不仅要对最值进行更新,
    // 同时也需要对每个最值对应的范围进行更新操作
    imax[node]=max(imax[node*2],imax[node*2+1]);
    if(imax[node]==imax[node*2]) section[node]=section[node*2];  //看看这个总的max是取了哪边区间的,对应更新其区间值
    else section[node]=section[node*2+1];

}
int main(){
    ll n,k,ma=0;
    cin>>n>>k;
    for(int i=0;i<n;i++){
        ll x,y,val;
        scanf("%lld%lld%lld",&x,&y,&val);
        v[y].push_back(wazxy(x,val,i+1));  //这里吧y时间结束的的放在一个容器中,避免了排序
        ma=max(ma,y);
    }
    build(1,1,ma);
    ll ans=0,l,r;
    for(int i=1;i<=ma;i++){
        update(1,1,ma,1,i,-k);
        for(auto it : v[i]) update(1,1,ma,1,it.l,it.val);
        pair<ll,ll> z=make_pair(imax[1],section[1]);
        if(z.first>ans){   //更新答案区间
            ans=z.first,l=z.second,r=i;
        }
    }
    if(ans==0) cout<<0<<endl;
    else{
        vector<ll> aa;   
        for(int i=l;i<=r;i++){
            for(auto it : v[i]){
                if(it.l>=l) aa.push_back(it.id);
            }
        }
        printf("%lld %lld %lld %d\n",ans,l,r,aa.size());
        for(auto it : aa) printf("%lld ",it);
        cout<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/xxxxxiao123/article/details/107234844