题目
思路
乍一看这个题,连 都无从下手呢。没想到正确思路竟然是枚举!
考虑最后所有人的 的交集,设其为 。那么一定满足这一点:
如果枚举 ,能不能快速确定 呢?答案是将 进行区间 ,然后求最大值。
显然每次都重新枚举所有区间不科学。好方法是 从大往小的枚举,遇到 则加入,遇到 则弹出。
用线段树维护这玩意儿就行了。复杂度 (因为可以离散化,值域可以更大)。
代码
#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;
}