数轴上有k种颜色共n个点,求一个最短的区间,包含所有k中颜色的点。
关键词:枚举区间终点、点的单调性(保证遍历时,每个点仅经过一次)
枚举区间的终点,对于每个终点,寻找比该终点坐标小的且离该点最近的k个不同颜色点,记录最大值即该终点对应最短区间长度。观察可以发现,这些k个点的坐标总是随终点的坐标减小而减小的。因此在遍历过程中,每个点最多仅经过一次,知道枚举到以某个点为终点时,不存在某种颜色的点在该终点左侧。
技巧:将相同颜色的点的坐标按照从大到小建边连接起来,可以依次遍历
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define maxn 2000000
#define ll long long
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int n,k;
struct Edge{
int to,next;
}edge[maxn];
int head[100],tot,node[maxn],cnt,ans;
void add(int u,int v){
edge[tot].to=v,edge[tot].next=head[u],head[u]=tot++;
}
bool cal(int u){
int mx=0;
for(int i=1;i<=k;i++){
while(edge[head[i]].to>u){
if(edge[head[i]].next==-1) return 0;
head[i]=edge[head[i]].next;
}
if(edge[head[i]].to<=u) mx=max(mx,u-edge[head[i]].to);
}
ans=min(ans,mx);
return 1;
}
int main(){
//freopen("a.txt","r",stdin);
scanf("%d%d",&n,&k);
mem(head,-1),tot=cnt=0,ans=INF;
int num,u;
for(int i=1;i<=k;i++){
scanf("%d",&num);
for(int j=1;j<=num;j++){
scanf("%d",&u);
add(i,u);
node[cnt++]=u;
}
}
sort(node,node+cnt);
for(int i=cnt-1;i>=0;i--){
if(node[i]!=node[i+1])
if(!cal(node[i])) break;
}
printf("%d\n",ans);
}