EF Java题解,代码已去除冗余~~~
可先按照线段末尾升序排列,并记载两个涂色的最末端位置,依次将线段优先放到末端最靠后的颜色(否则尝试放到末端靠前的颜色),如果遇到无法放入,则直接返回-1;最后需要注意的是,涂成紫色的线段至少要有一条,时间复杂度O(nlogn)
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),seg[][]=new int[n][],l1=-1,l2=-1;
for(int i=0;i<n;i++){
seg[i]=new int[]{sc.nextInt(),sc.nextInt(),i+1};
}
Arrays.sort(seg,(a,b)->Integer.compare(a[1],b[1]));
List<Integer> ans=new ArrayList<>();
for(int p[]:seg){
if(l1>=l2){
if(p[0]>l1){
l1=p[1];
ans.add(p[2]);
}
else if(p[0]>l2){
l2=p[1];
}
else{
System.out.println("-1");
return;
}
}
else{
if(p[0]>l2){
l2=p[1];
}
else if(p[0]>l1){
l1=p[1];
ans.add(p[2]);
}
else{
System.out.println("-1");
return;
}
}
}
if(ans.size()==0){
ans.add(1);
}
System.out.println(ans.size());
for(int a:ans){
System.out.print(a+" ");
}
}
}
可二分答案,对于指定的连通块最大值,依次对图进行深搜,并记录当前子树的连通块大小,若超过最大值,则需要将此节点涂色,时间复杂度O(nlogn)
import java.util.*;
public class Main{
public static void main(String args[]){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),k=sc.nextInt(),l=0,r=n;
List<Integer> path[]=new List[n+5];
for(int i=1;i<=n;i++){
path[i]=new ArrayList<>();
}
for(int i=0;i<n-1;i++){
int u=sc.nextInt(),v=sc.nextInt();
path[u].add(v);
path[v].add(u);
}
while(l<r){
int mid=(l+r)>>1;
if(find(1,0,mid,path)[1]<=k){
r=mid;
}
else{
l=mid+1;
}
}
System.out.println(r);
}
static int[] find(int k,int p,int max,List<Integer> path[]){
int ans[]=new int[]{1,0};
for(int a:path[k]){
if(a!=p){
int cur[]=find(a,k,max,path);
ans[1]+=cur[1];
ans[0]+=cur[0];
}
}
if(ans[0]>max){
ans[1]++;
ans[0]=0;
}
return ans;
}
}