[CF377D]Developing Game

题目

传送门 to luogu

思路

乍一看这个题,连 d p \tt dp 都无从下手呢。没想到正确思路竟然是枚举!

考虑最后所有人的 [ l i , r i ] [l_i,r_i] 的交集,设其为 [ L , R ] [L,R] 。那么一定满足这一点:

l i L v i R r i l_i\le L\le v_i\le R\le r_i

如果枚举 R R ,能不能快速确定 L L 呢?答案是将 [ l i , v i ] [l_i,v_i] 进行区间 + 1 +1 ,然后求最大值。

显然每次都重新枚举所有区间不科学。好方法是 R R 从大往小的枚举,遇到 r i r_i 则加入,遇到 v i 1 v_i-1 则弹出。

用线段树维护这玩意儿就行了。复杂度 O ( n log n ) \mathcal O(n\log n) (因为可以离散化,值域可以更大)。

代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long int_;
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline void writeint(int x){
	if(x < 0) putchar('-'), x = -x;
	if(x > 9) writeint(x/10);
	putchar((x%10)^48);
}

const int MaxN = 300000;

int v[MaxN<<1|1], lazy[MaxN<<1|1];
# define lson ((l+(l+r)/2)|(l!=(l+r)/2))
# define rson ((l+r)/2+1+r)|((l+r)/2+1!=r)
void pushDown(int l,int r){
	int &t = lazy[(l+r)|(l!=r)];
	v[lson] += t, lazy[lson] += t;
	v[rson] += t, lazy[rson] += t;
	t = 0; // 一定记得要清空
}
void pushUp(int l,int r){
	v[(l+r)|(l!=r)] = max(v[lson],v[rson]);
}

void modify(int ql,int qr,int adv=1,int l=1,int r=MaxN){
	int t = (l+r)|(l!=r);
	if(ql <= l && r <= qr){
		lazy[t] += adv, v[t] += adv;
		return ;
	}
// printf("[%d, %d]\n",l,r); getchar();
	pushDown(l,r);
	if(ql <= (l+r)/2) modify(ql,qr,adv,l,(l+r)>>1);
	if((l+r)/2 < qr) modify(ql,qr,adv,(l+r)/2+1,r);
	pushUp(l,r);
}

int query(int l=1,int r=MaxN){
	return v[(l+r)|(l!=r)];
}

struct People{
	int l, r, v, id;
	bool operator < (const People &q) const {
		return r < q.r;
	}
} p[MaxN];
vector< int > eraser[MaxN|1];
int susu[MaxN|1]; // 还原方案用的差分数组
int main(){
	int n = readint();
	for(int i=1; i<=n; ++i){
		p[i].l = readint();
		p[i].v = readint();
		p[i].r = readint();
		p[i].id = i;
	}
	sort(p+1,p+n+1), p[0].r = -1;
	int ans = 0; // final answer
	int rid = -1; // how to choose %r
	for(int r=MaxN,pid=n; r; --r){
		for(; p[pid].r == r; -- pid){
			modify(p[pid].l,p[pid].v);
			eraser[p[pid].v].push_back(p[pid].l);
		}
		int llb = query();
		if(ans < llb) ans = llb, rid = r;
		llb = eraser[r].size();
		for(int i=0; i<llb; ++i)
			modify(eraser[r][i],r,-1);
	}
	printf("%d\n",ans);
	for(int i=1; i<=n; ++i)
		if(p[i].v <= rid && rid <= p[i].r)
			++ susu[p[i].l], -- susu[p[i].v+1];
	int lid = -1;
	for(int l=1,now=0; l<=MaxN; ++l)
		if((now += susu[l]) == ans){
			lid = l; break;
		}
	for(int i=1; i<=n; ++i)
		if(p[i].v <= rid && rid <= p[i].r)
		if(p[i].l <= lid && lid <= p[i].v)
			printf("%d ",p[i].id);
	putchar('\n'); // 好习惯
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42101694/article/details/108038206