一维数组处理组队问题

此类问题的处理方法一般采用定一议二
POJ—1900:Moofest


思路: 树状数组

分析:

1 题目给定n头牛的听力v[i]. 现在规定两头你i和j如果要进行交流的话那么消耗的能量就是dis(i,j)max(v[i].v[j]),现在问n头牛总共的n(n-1)*2种方式消耗的总的能量

2 题目要求的是所有的牛的交流方式的总的消耗能量

看这个样例

3 1

2 5

2 6

4 3

那么所有的区间为[1.3],[1,5],[1,6],[3,5],[3,6],[5,6]

那么总和为4dis[1.3]+3dis[1,5]+3dis[1,6]+4dis[3,5]+4dis[3,6]+2dis[5,6] = 4*(dis[1.3]+dis[3,5]+dis[3,6])+3*(dis[1,5]+dis[1,6])+2*(dis[5,6]);

那么题目要求的ans = ∑(v[i]*(所有比v[i]小的牛的坐标的总和))

3 那么我们来分解这个式子,我们对点按照音量的值从小到大排完序之后

那么对于任一的一点i,i之前的牛的音量值肯定小于v[i],但是坐标的值可能比x[i]大也可能比x[i]小,因此我们应该分成两部分来考虑,就是坐标是i的左边和右边

首先考虑左边的情况,假设左边比小于等于v[i]的牛有三头坐标分别为a b c,那么左边的值就是v[i](x[i]-a)+v[i](x[i]-b)+v[i](x[i]-c) => v[i](3*x[i]-(a+b+c))

那么我们假设左边小于v[i]的牛有countLeft头,总的坐标为totalLeft,那么左边的值为v[i](countLeftx[i]-totalLeft);

接下来考虑右边的情况,由于我们已经按照v的值排序,那么我们能够很好的计算出小于等于v[i]的音量值的总的坐标之后,我们设为totalDis,那么根据左边求出的小于等于v[i]的个数为countLeft,那么右边的个数为i-countLeft,那么同理右边的坐标之和为totalDis-totalLeft , 那么右边的值为v[i]*(totalDis-totalLeft-(i-countLeft)*x[i]);

那么对于排序后的第i头牛来说比它小的音量的牛的值为v[i](countLeftx[i]-totalLeft)+v[i]*(totalDis-totalLeft-(i-countLeft)*x[i]);
4 我们已经知道了公式,现在我们只要去求countLeft和totalLeft即可,由于我们已经按照v的值排序, 那么我们只要对坐标建立两个树状数组即可。一个用来存储个数,一个用来存储坐标之和,那么对于第i头牛来说我们就能够在O(logn)的时间内求出countLeft和totalLeft

#include <iostream>
#include <cstring>
#include <stdio.h>
#include <algorithm>#define MAXSIZE 20005using namespace std;   //使用名称空间stdstruct cow
{long long vi, xi;     //听力值和位置
};long long val_sum_x[MAXSIZE];     //更新坐标值
long long val_x[MAXSIZE];         //更新位置
cow arry[MAXSIZE];int main()
{bool cmp(cow a, cow b);int lowbit(int x);void update_1(long long val[], long long i, long long cal, int arry_num);long long sum_pre_1(long long val[], int i);long long sum_between_1(long long val[], int pre, int last);int N;int left_x, right_x;long long left_sum, right_sum;long long sum_v;while (~scanf("%d", &N)){memset(val_x, 0, sizeof(val_x));memset(val_sum_x, 0, sizeof(val_sum_x));memset(arry, 0, sizeof(long long) * 2 * MAXSIZE);sum_v = 0;for (int i = 1;i <= N;i++)scanf("%lld%lld", &arry[i].vi, &arry[i].xi);sort(arry + 1, arry + 1 + N, cmp);for (int i = 1;i <= N;i++){update_1(val_x, arry[i].xi, 1, MAXSIZE);update_1(val_sum_x, arry[i].xi, arry[i].xi, MAXSIZE);left_x = sum_between_1(val_x, 1, arry[i].xi - 1);right_x = sum_between_1(val_x, arry[i].xi + 1, MAXSIZE);left_sum = sum_between_1(val_sum_x, 1, arry[i].xi - 1);right_sum = sum_between_1(val_sum_x, arry[i].xi + 1, MAXSIZE);sum_v = sum_v + arry[i].vi*(left_x*arry[i].xi - left_sum) + arry[i].vi*(right_sum - right_x * arry[i].xi);}printf("%lld\n", sum_v);}return 0;
}bool cmp(cow a, cow b)
{return a.vi < b.vi;
}int lowbit(int x)
{//返回二进制数最低位的1对应的数值return x & (-x);      //与运算
}//一维树状数组
void update_1(long long val[], long long i, long long cal, int arry_num)
{//原数组第i个元素加上cal,更新树状数组相关元素,arry_num为原数组的长度//可直接用于树状数组的建立for (;i <= arry_num;i += lowbit(i))val[i] += cal;
}long long sum_pre_1(long long val[], int i)
{//求arry数组的前i项和//val为树状数组地址long long sum = 0;for (;i > 0;i -= lowbit(i))       //从后向前每次跳一个lowbitsum += val[i];return sum;
}long long sum_between_1(long long val[], int pre, int last)
{//求原数组arry在区间[pre-last]的和return sum_pre_1(val, last) - sum_pre_1(val, pre - 1);
}

组队问题+数据离散化处理
hdu—3015:Disharmony Tree
思路与上题基本一致,只不过加上了数据离散化处理

#include <iostream>
#include <cstring>
#include <stdio.h>
#include <algorithm>#define MAXSIZE 100000using namespace std;   //使用名称空间stdstruct Tree
{long long xi, hi;    //x坐标位置和高度
};Tree tree[MAXSIZE];        //原数组
long long val_x[MAXSIZE];  //树状数组
long long val_num[MAXSIZE];      //计数树状数组int main()
{bool cmp_x(Tree a, Tree b);bool cmp_h_max(Tree a, Tree b);bool cmp_h(Tree a, Tree b);int lowbit(int x);void update_1(long long val[], long long i, long long cal, int arry_num);long long sum_pre_1(long long val[], int i);long long sum_between_1(long long val[], int pre, int last);int N;long long sum;      //计数器long long temp;     //标记记录器while (~scanf("%d", &N)){sum = 0;memset(tree, 0, sizeof(tree));memset(val_x, 0, sizeof(val_x));memset(val_num, 0, sizeof(val_num));for (int i = 1;i <= N;i++)scanf("%lld%lld", &tree[i].xi, &tree[i].hi);//输入完毕temp = 1;sort(tree + 1, tree + 1 + N, cmp_x);   //降序处理数据离散化for (int i = 1;i <= N;i++){if (tree[i].xi == tree[i+1].xi)tree[i].xi = temp;else{tree[i].xi = temp;temp=i+1;}}//x数据离散化完毕temp = 1;sort(tree + 1, tree + 1 + N, cmp_h);   //降序处理数据离散化for (int i = 1;i <= N;i++){if (tree[i].hi == tree[i+1].hi)tree[i].hi = temp;else{tree[i].hi = temp;temp=i+1;}}//h数据离散化完毕sort(tree + 1, tree + 1 + N, cmp_h_max);   //升序处理组队问题long long left_x, left_num, right_x, right_num;for (int i = 1;i <= N;i++){update_1(val_x, tree[i].xi, tree[i].xi, N);update_1(val_num, tree[i].xi, 1, N);left_x = sum_between_1(val_x, 1, tree[i].xi - 1);right_x = sum_between_1(val_x, tree[i].xi + 1, N);left_num = sum_between_1(val_num, 1, tree[i].xi - 1);right_num = sum_between_1(val_num, tree[i].xi + 1, N);sum = sum + tree[i].hi*(tree[i].xi*left_num - left_x) + tree[i].hi*(right_x - tree[i].xi*right_num);}printf("%lld\n", sum);}return 0;
}bool cmp_x(Tree a, Tree b)
{//降序——>离散化数据return a.xi < b.xi;
}bool cmp_h_max(Tree a, Tree b)
{//升序——>解决组对问题return a.hi > b.hi;
}bool cmp_h(Tree a, Tree b)
{//降序——>离散化数据return a.hi < b.hi;
}int lowbit(int x)
{//返回二进制数最低位的1对应的数值return x & (-x);      //与运算
}//一维树状数组
void update_1(long long val[], long long i, long long cal, int arry_num)
{//原数组第i个元素加上cal,更新树状数组相关元素,arry_num为原数组的长度//可直接用于树状数组的建立for (;i <= arry_num;i += lowbit(i))val[i] += cal;
}long long sum_pre_1(long long val[], int i)
{//求arry数组的前i项和//val为树状数组地址long long sum = 0;for (;i > 0;i -= lowbit(i))       //从后向前每次跳一个lowbitsum += val[i];return sum;
}long long sum_between_1(long long val[], int pre, int last)
{//求原数组arry在区间[pre-last]的和return sum_pre_1(val, last) - sum_pre_1(val, pre - 1);
}

树状数组相关应用之二元变量结构体组队问题相关推荐

  1. 树状数组相关应用之区间更新单点查询问题

    区间更新单点查询 树状数组的基本应用是单点更新,区间查询(例如求区间和). 鉴于树状数组的空间复杂度和时间复杂度都比线段树小 而且代码也短 所以就有大神用强大的脑洞YY出了区间修改+单点查询的树状数组 ...

  2. 树状数组相关应用之逆序对问题

    求逆序对 一元逆序对问题:POJ-2299 此题本质是一个求逆序对问题,对于一个无序数列,我们按照其顺序依次输入,并在每次输入时通过树状数组对已输入数列在其后方的序列进行个数求和,即可得到逆序数(先输 ...

  3. 树状数组相关应用之多叉树子树问题

    Poj-3321:Apple Tree 题意: 卡卡的房子外面有一棵苹果树.每年秋天,树上都会长出许多苹果.卡卡非常喜欢苹果,所以他一直在精心培育着这棵大苹果树. 这棵树有N个分叉,这些分叉由树枝相连 ...

  4. 树状数组相关应用之区间包含问题

    区间包含问题 对于一维区间问题一般是采用定一议二的方法 区间外包含问题:POJ-2481 对于此问题我们可以先按x升序排序(x值相同,y大的排在前面),保证之后输入的区间的左端必在之前输入区间之内,若 ...

  5. 树状数组相关应用之平面范围求和问题

    平面范围求和 此类问题实际上是树状数组推广到二维的情形 平面子矩阵求和:POJ-2352 此题是求[0–x][0–y]矩阵中除自身[x][y]外的求和 二维解法: #include <iostr ...

  6. 【模板】一维树状数组

    ACM模板 目录 聊聊前缀和 什么是树状数组? 树状数组相关操作 局限性 差分在树状数组中的应用 区间更新.单点查询 区间更新.区间查询 树状数组应用 聊聊前缀和 比如数组 int a[7]={1,2 ...

  7. 关于树状数组的个人理解

    本篇只对树状数组的理论部分进行讲解,其应用在之后的博客中再进行专题讲解 以下内容部分转载于: 彻底理解树状数组 树状数组彻底入门 树状数组(Binary Indexed Tree)--二进制索引树 树 ...

  8. python 树状数组_【算法日积月累】19-高级数据结构:树状数组

    树状数组能解决的问题 树状数组,也称作"二叉索引树"(Binary Indexed Tree)或 Fenwick 树. 它可以高效地实现如下两个操作: 1.数组前缀和的查询: 2. ...

  9. 树状数组的相关知识 及 求逆序对的运用

    文章目录 树状数组概念 前缀和和区间和 树状数组原理 区间和--单点更新 前缀和--区间查询 完整代码 离散化 sort函数 unique函数去重 erase函数仅保留不重复元素 通过树状数组求逆序对 ...

最新文章

  1. Android RecycleView 去掉默认动画
  2. cordova最基本的热更新
  3. (2.2)HarmonyOS鸿蒙页面跳转
  4. CRM管理系统、教育后台、赠品管理、优惠管理、预约管理、试听课、教师、学生、客户、学员、商品管理、科目、优惠券、完课回访、客户管理系统、收费、退费、回访、账号权限、订单流水、审批、转账、rp原型
  5. vsftp 使用虚拟用户
  6. 3-26 C++ 学习
  7. oracle中查找某用户执行某张表的操作操作记录
  8. Linux - vim安装 配置与使用
  9. if else终结者——策略模式
  10. Python爬虫:通过Selenium库学习如何爬取京东畅销排行榜书籍
  11. 22岁阻止席卷网络的病毒,却因开发恶意软件被捕,这是传奇黑客马库斯的故事...
  12. 政府推荐:房屋租赁合同电子版模板出租房个人住房商业租房Word协议书范本
  13. mac上传文件到ftp服务器,mac上传文件到ftp服务器
  14. mysql的填充因子_确定SQL Server填充因子(FILLFACTOR)值的方法
  15. 配置Atari Gym环境
  16. JVM系列之深入理解JVM(三)
  17. 抖音上坤之大强之作是什么意思
  18. 第五篇:uCOS-IInbsp;信号量及其…
  19. 巴西棕榈蜡的提取方式
  20. 关于Richard Stallman的若干惊人事实

热门文章

  1. 十年生死轮回,看国产手机发展四个阶段
  2. linux初始化进程
  3. 分享一个同行的blog,UI方面的。
  4. Ubuntu 之旅(三)安装通讯工具
  5. C# .NET学习经验总结
  6. Python面试题_中级版
  7. pyinstaller打包总结
  8. gcc编译出现dlopen、dlerror、dlsym、dlcolse的解决方法
  9. JAVA可检测异常和非检测异常
  10. 解决”java.lang.UnsatisfiedLinkError: Native Library .dll already loaded in another classloader”的问题