Intervals(POJ-1201)

Intervals

 POJ - 1201 

You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn. 
Write a program that: 
reads the number of intervals, their end points and integers c1, ..., cn from the standard input, 
computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i=1,2,...,n, 
writes the answer to the standard output. 

Input

The first line of the input contains an integer n (1 <= n <= 50000) -- the number of intervals. The following n lines describe the intervals. The (i+1)-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50000 and 1 <= ci <= bi - ai+1.

Output

The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i=1,2,...,n.

Sample Input

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

Sample Output

6

思路:

  • 贪心+树状数组
  • 贪心策略:先对这些区间的结束位置进行排序,然后尽量选择该区间靠后的点。如果当前区间的起始位置大于上一个区间的结束位置,那么只能重新开始选点;否则需要数出当前区间的起始位置到上一个区间的结束位置已经有多少个点,如果数出的点已经大于等于当前区间所要求的点,直接continue;否则还需要从当前区间的结束位置数出还需且未被标记过的点
  • 但是仅仅使用以上贪心策略会超时,时间复杂度在O(N^2),如果我们想知道当前区间到上一个区间的结束位置已经有多少点的话,需要O(N)的复杂度,但是可以使用树状数组进行优化,将时间复杂度降低到O(logN)

AcCode:

import java.util.Arrays;
import java.util.Scanner;

public class Main{
	//区间内有多少个点使用树状数组进行维护
	private static class TreeArrays{
		int[] arr = null;
		int[] treeArr = null;
		
		public TreeArrays(int n) {
			this.arr = new int[n];//原数组
			treeArr = new int[n];//树状数组
		}
		
		public void update(int i,int val) {
			int del = val-arr[i];
			arr[i] = val;
			
			while(i<treeArr.length) {
				treeArr[i] = treeArr[i] + del;
				i = i+lowbit(i);
			}
		}
		
		public int sum(int i,int j) {
			return sum(j)-sum(i-1);
		}
		
		public int sum(int i) {
			int sum = 0;
			while(i>0) {
				sum+=treeArr[i];
				i = i-lowbit(i);
			}
			return sum;
		}
		
		
		public int lowbit(int i) {
			return i&-i;
		}
		
		
		
	}
	
	private static class Qj implements Comparable<Qj> {
		int beginIndex;
		int endIndex;
		int needPoint;

		public Qj(int beginIndex, int endIndex, int needPoint) {
			this.beginIndex = beginIndex;
			this.endIndex = endIndex;
			this.needPoint = needPoint;
		}

		@Override
		public int compareTo(Qj o) {
			int res = endIndex - o.endIndex;
			if (res == 0) {
				return beginIndex - o.beginIndex;
			} else {
				return res;
			}
		}

		@Override
		public String toString() {
			// TODO Auto-generated method stub
			return beginIndex + " " + endIndex + " " + needPoint;
		}
	}

	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		Qj[] qjs = new Qj[n + 1];

		for (int i = 1; i <= n; i++) {
			qjs[i] = new Qj(in.nextInt(), in.nextInt(), in.nextInt());
		}
		Arrays.sort(qjs, 1, qjs.length);
//		for (Qj b : qjs) {
//			System.out.println(b);
//		}
		
		TreeArrays treeArrays = new TreeArrays(qjs[qjs.length - 1].endIndex + 1);
		
//		boolean[] isChoice = new boolean[qjs[qjs.length - 1].endIndex + 1];
		long count = qjs[1].needPoint;
		int lastIndex = qjs[1].endIndex;
		// 初始化
		for (int i = (int) (lastIndex - count + 1); i <= lastIndex; i++) {
			treeArrays.update(i, 1);
		}

		for (int i = 2; i < qjs.length; i++) {
			if(qjs[i].beginIndex>lastIndex) {
				count+=qjs[i].needPoint;
				lastIndex = qjs[i].endIndex;
				for (int j = qjs[i].endIndex; j >0 && j>=qjs[i].endIndex-qjs[i].needPoint+1; j--) {
					treeArrays.update(j, 1);
				}
			}else {
				int realdyPoint = treeArrays.sum(qjs[i].beginIndex, lastIndex);//已经有多少个点
//				for (int j = qjs[i].beginIndex; j <=lastIndex; j++) {
//					if(treeArrays.arr[])realdyPoint++;
//				}
				int syPoint = qjs[i].needPoint-realdyPoint;
				if(syPoint<=0)continue;
				lastIndex = qjs[i].endIndex;
				count+=syPoint;
				for (int j = qjs[i].endIndex; j >0 && j>=qjs[i].endIndex-qjs[i].needPoint+1 && syPoint>0; j--) {
					if(treeArrays.arr[j]==1)continue;
					syPoint--;
					treeArrays.update(j, 1);
				}
				
			}
		}
		System.out.println(count);
	}
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值