【CF337D】Developing Game(扫描线)(线段树)

传送门


题解:

这题做法挺多的,不过感觉扫描线要好写很多。

对于一个合法的选取集合 S S S,显然有 max ⁡ i ∈ S l i ≤ min ⁡ i ∈ S v i ≤ max ⁡ i ∈ S v i ≤ min ⁡ i ∈ S r i \max_{i\in S}l_i\leq \min_{i\in S}{v_i}\leq \max_{i\in S}v_i\leq \min_{i\in S}r_i maxiSliminiSvimaxiSviminiSri,也就是说一定存在 L ∈ [ max ⁡ i ∈ S l i , min ⁡ i ∈ S v i ] , R ∈ [ max ⁡ i ∈ S v i , min ⁡ i ∈ S r i ] L\in[\max\limits_{i\in S}{l_i},\min\limits_{i\in S}v_i],R\in [\max\limits_{i\in S}v_i,\min\limits_{i\in S}r_i] L[iSmaxli,iSminvi],R[iSmaxvi,iSminri]

我们把一个合法的 [ L , R ] [L,R] [L,R]看作是一个平面上的点,一个人看作是 [ l , v ] × [ v , r ] [l,v]\times [v,r] [l,v]×[v,r]的矩形,问题就成了选择一个被矩形覆盖次数最多的点,线段树维护扫描线即可


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const

namespace IO{
	inline char get_char(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	template<typename T>
	inline T get(){
		char c;T num;
		while(!isdigit(c=gc()));num=c^48;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return num;
	}
	inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;
using pii=std::pair<int,int>;
#define fi first
#define se second

cs int N=1e5+7,M=3e5,SIZE=(M+7)<<2;

int n;

struct modi{int l,r,t;};
std::vector<modi> vec[M+7];

pii mx[SIZE];int add[SIZE];

#define lc u<<1
#define rc u<<1|1
inline void pushup(int u){mx[u]=std::max(mx[lc],mx[rc]);}
inline void pushadd(int u,int ad){add[u]+=ad;mx[u].fi+=ad;}
inline void pushdown(int u){if(add[u]){pushadd(lc,add[u]);pushadd(rc,add[u]);add[u]=0;}}
inline void build(int u,int l,int r){
	if(l==r){mx[u].se=l;return ;}
	int mid=l+r>>1;
	build(lc,l,mid);build(rc,mid+1,r);
	pushup(u);
}
inline void modify(int u,int l,int r,int ql,int qr,int v){
	if(ql<=l&&r<=qr)return pushadd(u,v);
	int mid=l+r>>1;pushdown(u);
	if(ql<=mid)modify(lc,l,mid,ql,qr,v);
	if(mid<qr)modify(rc,mid+1,r,ql,qr,v);
	pushup(u);
}
#undef lc
#undef rc
int ans,L,R;
int l[N],r[N],vl[N];
signed main(){
#ifdef zxyoi
	freopen("game.in","r",stdin);
#endif
	n=gi();
	for(int re i=1;i<=n;++i){
		int l=::l[i]=gi(),v=vl[i]=gi(),r=::r[i]=gi();
		if(l>v||v>r)continue;
		vec[v].push_back((modi){l,v,1});
		vec[r+1].push_back((modi){l,v,-1});
	}build(1,1,M);
	for(int re i=1;i<=M;++i)if(vec[i].size()){
		for(auto t:vec[i])modify(1,1,M,t.l,t.r,t.t);
		if(mx[1].fi>ans){
			ans=mx[1].fi;
			L=mx[1].se;
			R=i;
		}
	}
	cout<<ans<<"\n";
	for(int re i=1;i<=n;++i)if(l[i]<=L&&L<=vl[i]&&vl[i]<=R&&R<=r[i])cout<<i<<" ";
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值