其他分享
首页 > 其他分享> > POJ1990 - MooFest - Indexed Tree求区间和

POJ1990 - MooFest - Indexed Tree求区间和

作者:互联网

POJ1990 - MooFest

Description
每年,农场主约翰的N头(1<=N<=20000)奶牛都会参加“MooFest”,这是一个来自世界各地奶牛的社交聚会。
MooFest包括各种各样的活动,包括堆放草包、跳栏、把尾巴钉在农夫身上,当然还有哞哞叫。
当奶牛们排成一队参加某一特定活动时,它们发出的哞哞声几乎震耳欲聋。年复一年地参加这个活动后,有些奶牛实际上失去了一点听力。
每头母牛i都有一个相关的“听力”阈值v(i)(范围为1..20000)。如果一头牛对一头牛i发哞哞声,她必须使用至少是两头牛之间距离v(i)倍的音量,才能被一头牛i听到。
如果两头母牛i和j想要交谈,它们说话的音量必须等于它们之间的距离乘以max(v(i),v(j))。
假设N头奶牛中的每一头都站在一条直线上(每头奶牛在1..20000范围内的某个唯一x坐标处),每对奶牛都在用最可能小的音量进行对话。

计算所有N(N-1)/2对哞哞声产生的所有音量之和。


Input
第1行:整数,N
第2~N+1行:两个整数:牛的听力阈值和x坐标。第2行代表第一头牛;第3行代表第二头牛;等等。
没有两头母牛会站在同一个地方。

Output
第1行:包含一个整数,整数是所有正在交谈的奶牛的音量总和。

Sample Input
4
3 1
2 5
2 6
4 3

Sample Output
57

 


 

思路分析:

以题目所给用例为例:

 

 

1. 如果两头牛i和j想要交谈,它们说话的音量必须等于它们之间的距离乘以max(v(i),v(j)) ==> 当前坐标的牛说话,只有阈值不大于它的牛,才能听见
所以,计算当前牛的音量之和时,需要知道所有比它音量阈值小的牛,那么我们需要按照牛的音量阈值顺序计算;

2. 以坐标3的牛为例:音量之和 = 3左边的音量之和 + 3右边的音量之和
  3左边的音量之和 = ( 3 - 1 )* 4
  3右边的音量之和 = ( 5 - 3 ) * 4 + ( 6 - 3)* 4 = ((5 + 6) - 2 * 3 ) * 4
  以上计算公式时的5+6是3以右的牛的坐标之和,2*3中的2是3以右的牛的个数;
  那么可以分别求出左边和右边的距离,然后统一乘以音量阈值;
  左侧距离和=牛的个数*当前牛的坐标 - 左边坐标之和;右侧距离和=右边坐标之和-牛的个数*当前牛的坐标
  所以,我们需要解决的问题变为:分别求两个区间【0~当前牛的坐标-1,当前牛的坐标+1~最后】内牛的个数之和,牛的坐标之和。

由此,问题变更为求区间和的问题,那么可使用Indexed Tree解决。

 

package tree;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.StringTokenizer;

/**
 * 
 * 
 * 思路:
 * 根据听力阈值排序
 * 按听力阈值顺序遍历
 * 两个indexed tree
 * 一个保存比当前牛听力小的牛的个数,阈值对应的tree1[i]:有牛,则为1,没有则为0(求和)
 * 一个保存比当前牛听力小的牛的坐标,阈值对应的tree2[i]:牛的坐标(求和)
 * 
 * 左侧:query1: 0~当前阈值-1处的tree1之和cntSum,query2:0~当前阈值-1处的tree2之和indexSum
 * 左侧距离和:cntSum*当前牛的坐标-indexSum
 * 右侧:query1:当前阈值+1~最后2*offset-1处的tree1之和cntSum,query2:当前阈值+1~最后2*offset-1处的tree2之和indexSum,
 * 右侧距离和:indexSum-cntSum*当前牛的坐标
 * 
 * 音量总和 = (左侧距离和+右侧距离和)*当前牛的听力阈值
 * 
 * @author XA-GDD
 *
 */
public class POJ1990_MooFest {
	static int N;
	static int _Max_N = 20000;
	static int [][] srcArr = new int[_Max_N][2];
	static int [] cntIdxTree = new int[4*_Max_N];
	static int [] coordIdxTree = new int[4*_Max_N];
	static int offset;
	static long ans = 0;
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st;
        while (br.ready()) {
        	st = new StringTokenizer(br.readLine());
        	N = Integer.parseInt(st.nextToken());
        	
        	int maxIndex = 0;
        	for(int i=0;i<N;i++) {
        		st = new StringTokenizer(br.readLine());
        		srcArr[i][0] = Integer.parseInt(st.nextToken());
        		srcArr[i][1] = Integer.parseInt(st.nextToken());
        		maxIndex = Math.max(maxIndex, srcArr[i][1]);
        	}
        	
        	//根据听力阈值排序
        	Arrays.sort(srcArr,0,N, new Comparator<int []>() {
				@Override
				public int compare(int[] o1, int[] o2) {
					return o1[0]-o2[0];
				}
			});
        	
        	//初始化
        	int k=0;
        	while((1<<k)<maxIndex) {
        		k++;
        	}
        	offset = 1<<k;
        	
        	for(int i=0;i<N;i++) {
        		
        		//srcArr[i][0]:音量阈值, srcArr[i][1]:坐标 
        		
        		long [] leftRes = query(offset,offset+srcArr[i][1]-1);
	        	//左侧距离和:牛的个数*当前牛的坐标 - 左边坐标之和
        		long leftDist = leftRes[0]*srcArr[i][1] - leftRes[1];
        		
        		long [] rightRes = query(offset+srcArr[i][1]+1,2*offset-1);
        		//右侧距离和:右边坐标之和 - 牛的个数*当前牛的坐标
        		long rightDist = rightRes[1] - rightRes[0]*srcArr[i][1] ;
        		
        		ans += (leftDist+rightDist) * srcArr[i][0];
        		update(offset+srcArr[i][1],srcArr[i][1]);
        	}
        	
        	System.out.println(ans);
        }
	}
	
	//更新牛的数量及坐标,牛的个数每次都是+1,因此update更新value只传x坐标
	static void update(int index ,int x){
		cntIdxTree[index] += 1;
		coordIdxTree[index] = x;
		index = index >> 1;
		while(index>0) {
			cntIdxTree[index] = cntIdxTree[index*2] + cntIdxTree[index*2+1];
			coordIdxTree[index] = coordIdxTree[index*2] + coordIdxTree[index*2+1];
			index = index >> 1;
		}
	}
	
	//求区间和
	static long[] query(int start ,int end) {
		long count = 0L;
		long coordSum = 0L;
		while(start<=end) {
			if(start%2==1) {
				count += cntIdxTree[start];
				coordSum +=  coordIdxTree[start];
			}
			if(end%2==0) {
				count += cntIdxTree[end];
				coordSum +=  coordIdxTree[end];
			}
			start = ( start + 1 ) >> 1;
			end = ( end - 1 ) >> 1;
		}
		return  new long[] {count,coordSum};
	}

}

  

 

 

标签:index,阈值,int,Tree,音量,POJ1990,Indexed,static,坐标
来源: https://www.cnblogs.com/smile_to_warm/p/15074757.html