题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=6022
题目大意:多个线段,每个线段中的整数点可以放一个标记,要求每个整数点不同,问最多能放多少个线段
题目思路:也想到了先按左端点排序再按右端点排序,但是没想到正确的贪心策略,一直是直接整体进行处理,使得pos=max(pos+1,a[i].l),但是很明显这是不对的,可以发现(1,1) (2,2) (1,3)这个样例,排序后是(1,1) (1,3) (2,2),要是这么做答案就只有2了,但是实际上应该是3。正确的解法应该是,优先队列维护包含pos的所有线段,然后优先队列按照右端点从小到大排序,因为对到达pos后,左端点已经没啥用了,因为pos一定是从小到大跑的,所以右端点越小说明它能够起的范围越小,就得先搞它。作为一名菜鸡,即使知道了正解,代码实现居然成了问题..笑容逐渐消失。首先先让整个序列按照左端点从小到大,这样最小的点一定是要选的,同时让pos=a[1].l,然后就可以发现,到a[i].l!=pos的时候,这些段一定是不包含pos的,所以在这个时候就要处理之前队列存的东西了。当pos<a[i].l的时候,a[i]线段都不能参与战斗,这个时候就按照之前队列中的r逐步推进pos,如果=,那么a[i]也能加入战斗,无论是因为a[i]能加入战斗导致的while退出还是队列空了队列推出,pos都更新成a[i].l。最后需要自己建立一个a[i].l=1e9+5的点,来帮助最后一批队列中的老鸽能够完成任务
以下是代码:
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define inf 0x7fffffff
const int MAXN = 3e5+5;
struct node{
int l,r;
bool operator <(const node &a) const{
return r>a.r;
}
}a[MAXN];
priority_queue<node>q;
bool cmp(node a,node b){
return a.l<b.l;
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
while(!q.empty())q.pop();
rep(i,1,n){
scanf("%d%d",&a[i].l,&a[i].r);
}
int pos=a[1].l,ans=0;
a[n+1].l=1e9+5;
sort(a+1,a+n+1,cmp);
rep(i,1,n+1){
if(pos!=a[i].l){
while(!q.empty()&&pos<a[i].l){
if(q.top().r>=pos)ans++,pos++;
q.pop();
}
pos=a[i].l;
}
q.push(a[i]);
}
printf("%d\n",ans);
}
return 0;
}