[CF377D][线段树][扫描线]Developing Game

CF377D

l , r l,r l,r看成两维坐标,假设最后有解,那一定存在一个 ( L , R ) (L,R) (L,R)使得 L ≥ m a x { l [ i ] } , L ≤ m i n { v [ i ] } L\ge max\{l[i]\},L\le min\{v[i]\} Lmax{l[i]}Lmin{v[i]} R ≥ m a x { v [ i ] } , R ≤ m i n { r [ i ] } R\ge max\{v[i]\},R\le min\{r[i]\} Rmax{v[i]}Rmin{r[i]},否则显然不满足条件
即是把 l , v , r l,v,r l,v,r看作一个横坐标 ( l , v ) (l,v) (l,v)纵坐标 ( v , r ) (v,r) (v,r)的矩形,要求尽量多的矩形使得它们的面积并不为空(可以为0,就是矩形并为一个点的情况)
那就可以线段树+扫描线了

Code:

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=3e5+5;
namespace segtree{
	struct seg{int l,r,add,mxv,mxr;}tr[N<<2];
	#define ls tr[k].l
	#define rs tr[k].r
	#define mid (ls+rs>>1)
	inline void pushup(int k){
		if(tr[k<<1].mxv>tr[k<<1|1].mxv) tr[k].mxr=tr[k<<1].mxr;
		else tr[k].mxr=tr[k<<1|1].mxr;
		tr[k].mxv=max(tr[k<<1].mxv,tr[k<<1|1].mxv);
	}
	inline void pushadd(int k,int v){tr[k].add+=v;tr[k].mxv+=v;}
	inline void pushdown(int k){
		if(tr[k].add){
			pushadd(k<<1,tr[k].add);
			pushadd(k<<1|1,tr[k].add);
			tr[k].add=0;
		}
	}
	inline void build(int k,int l,int r){
		ls=l,rs=r,tr[k].mxr=r,tr[k].mxv=0;
		if(l==r) return;
		build(k<<1,l,mid);build(k<<1|1,mid+1,r);
	}
	inline void modify(int k,int ql,int qr,int v){
		if(qr<ls || ql>rs) return;
		if(ql<=ls && rs<=qr) return pushadd(k,v);
		pushdown(k);
		if(qr<=mid) modify(k<<1,ql,qr,v);
		else if(ql>mid) modify(k<<1|1,ql,qr,v);
		else modify(k<<1,ql,mid,v),modify(k<<1|1,mid+1,qr,v);
		pushup(k);
	}
}
using namespace segtree;
struct sqr{
	int l,r,id;
	sqr(){}
	sqr(int _l,int _r,int _id):l(_l),r(_r),id(_id){}
};
vector<sqr>add[N],del[N];
int x[N],y[N],v[N];
int mx=0,ansl,ansr;
int ans[N],cnt=0;
int main(){
	build(1,1,300000);
	int n=read();
	for(int i=1;i<=n;i++){
		x[i]=read();v[i]=read();y[i]=read();
		int l=x[i],r=y[i];
		add[l].pb(sqr(v[i],r,i));
		del[v[i]].pb(sqr(v[i],r,i));
	}
	for(int i=1;i<=300000;i++){
		for(int j=0;j<add[i].size();j++){
			int l=add[i][j].l,r=add[i][j].r;
			modify(1,l,r,1);
		}
		int nmx=tr[1].mxv;
		if(nmx>mx){mx=nmx,ansl=i;ansr=tr[1].mxr;}
		for(int j=0;j<del[i].size();j++){
			int l=del[i][j].l,r=del[i][j].r;
			modify(1,l,r,-1);
		}
	}
	cout<<mx<<"\n";
	for(int i=1;i<=n;i++) if(x[i]<=ansl && y[i]>=ansr && v[i]>=ansl && v[i]<=ansr) ans[++cnt]=i;
	for(int i=1;i<=cnt;i++) cout<<ans[i]<<" ";
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值