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':' ');
		}
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章