CF-1250C-Trip to Saint Petersburg(线段树)

题目链接:https://codeforces.com/contest/1250/problem/C

题目大意:给出一个无限长度的数轴。数轴上的每个点的权值都为-k。其中有n个奖励区间。即选取一个区间后,如果该区间覆盖奖励区间,则区间之和会加上奖励区间的分数。求一个区间的最大分数,输出这个区间和覆盖的奖励区间。

思路:由于奖励区间的范围比较小,所以很容易想到,枚举右端点r,找到左端点l,维护奖励值。从左到右,每读入一个点,首先将[1,r]区间都-k。然后再判断是否r是一个奖励区间的右端点。如果有新加的奖励区间,则所有i<l处的区间都+val,表示前面的去缉拿都可以获得这个奖励值。然后区间查询最值就好了。

ACCode:

#include<stdlib.h>
#include<string.h>
#include<stdio.h>
#include<time.h>
#include<math.h>
// srand((unsigned)time(NULL));rand();
      
#include<map>//unordered_map
#include<set>//multiset
#include<deque>
#include<queue>
#include<stack>
#include<bitset>
#include<string>
#include<fstream>
#include<iostream>
#include<algorithm>
 
#define ll long long
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define clean(a,b) memset(a,b,sizeof(a))
using namespace std;
      
const int MAXN=2e5+10;
//const int MAXM=10;
const int INF32=0x3f3f3f3f;
const ll INF64=0x3f3f3f3f3f3f3f3f;
const ll MOD=1e9+7;
const double PI=acos(-1.0);
const double EPS=1.0e-8;
//unsigned register
// ios::sync_with_stdio(false)

struct SegTree{
	struct Tree{
		int l,r,len;
		ll val,maxval;int pos;
		ll lazy;
	};
	Tree T[MAXN<<2];
	
	void PushUp(int rt){
		T[rt].val=T[rt<<1].val+T[rt<<1|1].val;
		T[rt].maxval=max(T[rt<<1].maxval,T[rt<<1|1].maxval);
		if(T[rt<<1].maxval>T[rt<<1|1].maxval) T[rt].pos=T[rt<<1].pos;
		else T[rt].pos=T[rt<<1|1].pos;
	}
	void PushDown(int rt){
		if(T[rt].lazy!=0){
			T[rt<<1].lazy+=T[rt].lazy;
			T[rt<<1|1].lazy+=T[rt].lazy;
			
			T[rt<<1].maxval+=T[rt].lazy;
			T[rt<<1|1].maxval+=T[rt].lazy;
			T[rt<<1].val+=T[rt].lazy*T[rt<<1].len;
			T[rt<<1|1].val+=T[rt].lazy*T[rt<<1|1].len;
			
			T[rt].lazy=0;
		}
	}
	void Build(int l,int r,int rt){
		T[rt].l=l;T[rt].r=r;T[rt].len=r-l+1;
		T[rt].lazy=0;
		if(l==r){
			T[rt].maxval=0;//T[rt].val=0;
			T[rt].pos=l;
			return ;
		}
		int mid=(l+r)>>1;
		Build(l,mid,rt<<1);Build(mid+1,r,rt<<1|1);
		PushUp(rt);
	}
	void Update(int ql,int qr,ll val,int rt){
		if(ql<=T[rt].l&&T[rt].r<=qr){
//			T[rt].val+=val*T[rt].len;
			T[rt].maxval+=val;
			T[rt].lazy+=val;
			return ;
		}PushDown(rt);
		if(qr<=T[rt<<1].r) Update(ql,qr,val,rt<<1);
		else if(ql>=T[rt<<1|1].l) Update(ql,qr,val,rt<<1|1);
		else{
			Update(ql,qr,val,rt<<1);
			Update(ql,qr,val,rt<<1|1);
		}PushUp(rt);
	}
	PLL QueryMax(int ql,int qr,int rt){
		if(ql<=T[rt].l&&T[rt].r<=qr) return make_pair(T[rt].maxval,T[rt].pos);
		PushDown(rt);
		if(qr<=T[rt<<1].r) return QueryMax(ql,qr,rt<<1);
		else if(ql>=T[rt<<1|1].l) return QueryMax(ql,qr,rt<<1|1);
		else{
			PLL tmpl=QueryMax(ql,qr,rt<<1),tmpr=QueryMax(ql,qr,rt<<1|1);
			if(tmpl.first>tmpr.first) return tmpl;
			else return tmpr;
		}
	}
};
struct Line{
	int l,r,id;
	ll val;
	friend int operator < (Line a,Line b){
		return a.r<b.r;
	}
};
SegTree Seg;
Line In[MAXN];
int Ans[MAXN],Acnt;
int n;ll k;

int main(){
	while(~scanf("%d%lld",&n,&k)){
		for(int i=1;i<=n;++i){
			scanf("%d%d%lld",&In[i].l,&In[i].r,&In[i].val);In[i].id=i;
		}sort(In+1,In+1+n);
		int tmp=In[n].r;
		Seg.Build(1,tmp,1);
		ll ans=0;int ansl,ansr;
		for(int i=1,j=1;i<=tmp&&j<=n;++i){
			Seg.Update(1,i,-k,1);//前面任何一个左端点,带上这个点的值 
			while(In[j].r==i){//有满足的区间 
				Seg.Update(1,In[j].l,In[j].val,1);
				++j;
			}
			PLL res=Seg.QueryMax(1,i,1);
			if(res.first>ans){
				ans=res.first;ansl=res.second;ansr=i;
			}
		}
		if(ans==0){
			printf("0\n");continue ;
		}
		printf("%lld %d %d ",ans,ansl,ansr);
		Acnt=0;
		for(int i=1;i<=n;++i){
			int l=In[i].l,r=In[i].r,id=In[i].id;
			if(ansl<=l&&r<=ansr) Ans[++Acnt]=id;
		}printf("%d\n",Acnt);
		for(int i=1;i<=Acnt;++i){
			printf("%d%c",Ans[i],i==Acnt?'\n':' ');
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值