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