题意:有许多任务,给你开始时间和结束时间。问最少几台机器可以完成,最小工作时间(每台机器的时间是第一个任务的开始时间到最后一个任务的结束时间)
思路:先来看这么一个问题,多次给一段区间内的数加上某个数,问最大的数是几,比如给[3,5]加上2,最方便的做法是,给开始3打上个记号2,给结束5后的数6,打记号上-2。求一遍前缀和,中间最大的sum就是最大的数。
回到这个问题,最少几台机器,假若某个时间点有m个任务,那需要m台机器。我们给开始时间打记号1,结束时间打记号-1。前缀和中最大的就是最少的机器,和上面的例子很像。这个时间跨度大,不适合开数组,可以每个任务记录两个点,排序(同一时间,结束的点排前面),遍历一遍,开始的点sum+1,结束的点sum-1。机器时间和的话,每次ans更新的时候,就是要开新的机器了,记录下这个点的时间(开始)。结束时间,反着遍历,同样的方式记录。
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<stdlib.h>
#include<math.h>
#include<vector>
#include<list>
#include<map>
#include<stack>
#include<queue>
#include<algorithm>
#include<numeric>
#include<functional>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 2e5+5;
int t1[maxn],t2[maxn];
struct data
{
int index,st;
}node[maxn*2];
int cmp(const data &a,const data &b)
{
if(a.index == b.index)
return a.st < b.st;
else
return a.index < b.index;
}
int main(void)
{
int T,n;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i = 0; i < n; i++)
{
int a,b;
scanf("%d%d",&a,&b);
node[2*i].index = a;
node[2*i].st = 1;
node[2*i+1].index = b;
node[2*i+1].st = 0;
}
sort(node,node+2*n,cmp);
int ans = 0,sum = 0;
for(int i = 0; i < 2*n; i++)
{
if(node[i].st)
{
sum++;
if(sum > ans)
{
ans = sum;
t1[ans] = node[i].index;
}
}
else
sum--;
}
int ans2 = 0;
sum = 0;
for(int i = 2*n-1; i >= 0; i--)
{
if(!node[i].st)
{
sum--;
if(sum < ans2)
{
ans2 = sum;
t2[-ans2] = node[i].index;
}
}
else
sum++;
}
ll time = 0;
for(int i = 1; i <= ans; i++)
time += t2[i] - t1[i];
printf("%d %lld\n",ans,time);
}
return 0;
}