原题链接:蓝桥杯历届试题-小朋友排队
解题思路:尝试使用了比树状数组功能更强大的线段树,线段树可以解决所有用树状数组解决的题,唯一缺点就是需要开辟4*n的大小才能保证不溢出。
注意事项:
对于本题来说,即求数组中某数的逆序对,然后求其等差数列的和即可。本代码没有构造权值线段树的过程,而是直接进行update操作,免去了建树的时间。需要注意的是,需要对给定数组进行两次遍历,一次得到前置逆序,一次得到后置逆序,最后拼接结果即可。
看到有佬还是用了lazy标记让我很不解。。为什么对这样单点修改更新的操作还需要延迟呢?
总的来说,本题算是一道树状数组和线段树的模板题
参考代码:
import java.io.*; // 蓝桥杯历届试题-小朋友排队 - C语言网 (dotcpp.com) public class Main { static StreamTokenizer cin; static PrintWriter out; static int n; // 小朋友的个数 static int[] arr; // 小朋友身高 static long[] cnt; // 每个小朋友最少需要交换的次数 static int[] treeArr; static int maxN = -1; // 存储上值域 public static void main(String[] args) throws IOException { cin = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in))); out = new PrintWriter(new OutputStreamWriter(System.out)); n = nextInt(); arr = new int[n+1]; cnt = new long[n+1]; for(int i = 1; i < n+1; i++){ int num = nextInt(); arr[i] = num; maxN = Math.max(maxN, num); } treeArr = new int[(maxN << 2)+10]; for(int i = 1; i < n+1; i++){ update(0, 0, maxN, arr[i]); // 存储i左边比arr[i]大的元素 cnt[i] += query(0, 0, maxN, arr[i]+1, maxN); } // 重构 treeArr = new int[4*maxN +10]; for(int i = n; i > 0; i--){ update(0, 0, maxN, arr[i]); // 存储i右边比arr[i]小的元素 cnt[i] += query(0, 0, maxN, 0, arr[i]-1); } long res = 0; for(int i = 1; i < n+1; i++){ res += cnt[i]*(cnt[i] + 1)/2; } out.println(res); out.flush(); } // 单点修改, 不需要lazy标记, L和R为此节点值域范围 static void update(int node, int L, int R, int value){ if(L == value && R == value){ // 叶子 treeArr[node]++; // 重复值++ return; } int mid = (L+R) >> 1; int leftNode = (node << 1) + 1; int rightNode = leftNode + 1; if(value = L) update(leftNode, L, mid, value); // 更新左子树 if(value = mid+1) update(rightNode, mid+1, R, value); // 更新右子树 treeArr[node] = treeArr[leftNode] + treeArr[rightNode]; } // 查询[value, maxN]间的元素个数 static long query(int node, int L, int R, int QL, int QR){ if(QL > R || L > QR) return 0; if(QL = R) // 完全覆盖 return treeArr[node]; int mid = (L + R) >> 1; int leftNode = (node << 1) + 1; int rightNode = leftNode + 1; long result = 0; if(!(QL > mid)) result += query(leftNode, L, mid, QL, QR); if(!(QR < mid+1)) result += query(rightNode, mid+1, R, QL, QR); return result; } static int nextInt() throws IOException{ cin.nextToken(); return (int)cin.nval; } }
0.0分
1 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复