HDU 3473 Minimum Sum (划分树求区间第k大带求和)(转)
题意:在区间中找一个数,求出该区间每个数与这个数距离的总和,使其最小
找的数字是中位数(若是偶数个,则中间随便哪个都可)接着找到该区间比此数大的数的总和
区间中位数可以使用划分树,然后在其中记录:每层的 1-i 中划分到左区间的总和
划分树:
划分树是一种基于线段树的数据结构。主要用于快速求出(在log(n)的时间复杂度内)序列区间的第k大值 。
划分树和归并树都是用线段树作为辅助的,原理是基于快排 和归并排序 的。
划分树的建树过程基本就是模拟快排过程,取一个已经排过序的区间中值,然后把小于中值的点放左边,大于的放右边。并且记录d层第i个数之前(包括i)小于中值的放在左边的数。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define dir(a,b) (a>>b)
const int Max=1e5+;
int orval[Max];
int dsegtr[][Max];//记录第i层划分树的序列
int lele[][Max];//记录第i层的1-i划分到左子树的元素个数(包括i)
long long sum[][Max],psum[Max],lsum;//每层的1-i中划分到左区间的总和
void Create(int sta,int enn,int cur)
{
int mid=dir(sta+enn,);
int lsame=mid-sta+;//此区间左边不小于orval[mid]的个数
int lsta=sta,rsta=mid+;
for(int i=sta; i<=mid; ++i)
{
if(orval[i]<orval[mid])
lsame--;
}
for(int i=sta; i<=enn; ++i)//给下一层赋值
{
sum[cur][i]=sum[cur][i-];
if(i==sta)
{
lele[cur][i]=;//表示[l, i]内有多少个数分到左边
}
else
{
lele[cur][i]=lele[cur][i-]; }
if(dsegtr[cur][i]==orval[mid])
{
if(lsame)
{
sum[cur][i]+=dsegtr[cur][i];
lsame--;
lele[cur][i]++;
dsegtr[cur+][lsta++]=dsegtr[cur][i];//相当于移动元素到左边
}
else
{
dsegtr[cur+][rsta++]=dsegtr[cur][i];//相当于移动元素到右边
}
}
else if(dsegtr[cur][i]<orval[mid])
{
sum[cur][i]+=dsegtr[cur][i];
lele[cur][i]++;
dsegtr[cur+][lsta++]=dsegtr[cur][i];
}
else
{
dsegtr[cur+][rsta++]=dsegtr[cur][i];
}
}
if(sta==enn)
return;
Create(sta,mid,cur+);
Create(mid+,enn,cur+);
return;
}
int Query(int sta,int enn,int cur,int lef,int rig,int k)
{
int lsame;//[sta, lef)内将被划分到左子树的元素数目
int rsame;//[lef,rig]内将被划分到左子树的元素数目 关键
int mid=dir(sta+enn,);
if(sta==enn)
return dsegtr[cur][sta];
if(sta==lef)//特判
{
lsame=;
rsame=lele[cur][rig];
}
else
{
lsame=lele[cur][lef-];
rsame=lele[cur][rig]-lsame;
}
if(k<=rsame)
{
return Query(sta,mid,cur+,sta+lsame,sta+lsame+rsame-,k);//关键
}
else
{
lsum+=sum[cur][rig]-sum[cur][lef-];//所求值不在左区间
return Query(mid+,enn,cur+,mid-sta++lef-lsame,mid-sta++rig-lsame-rsame,k-rsame);//关键
}
}
long long Solve(long long temp,int rig,int lef,int k)
{
long long resr=psum[rig]-psum[lef-]-lsum-temp-(long long)(rig-lef+-k)*temp;
long long resl=(long long)(k-)*temp-lsum;
return resr+resl;
}
int main()
{
int n,m,t,coun=;
int lef,rig;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=;i<;++i)
sum[i][]=0ll;
psum[]=0ll;
for(int i=; i<=n; ++i)
{
scanf("%d",&orval[i]);
psum[i]=psum[i-]+orval[i];
dsegtr[][i]=orval[i];
sum[][i]=sum[][i-]+orval[i];
}
sort(orval+,orval+n+);
Create(,n,);
scanf("%d",&m);
printf("Case #%d:\n",++coun);
for(int i=; i<m; ++i)
{
lsum=0ll;
scanf("%d %d",&lef,&rig);
lef++,rig++;
int temp=Query(,n,,lef,rig,(rig-lef+>>));
printf("%I64d\n",Solve(temp,rig,lef,(rig-lef+>>)));
}
printf("\n");
}
return ;
}
参考:http://www.cnblogs.com/pony1993/archive/2012/07/17/2594544.html
HDU 3473 Minimum Sum (划分树求区间第k大带求和)(转)的更多相关文章
- [hdu2665]Kth number(划分树求区间第k大)
解题关键:划分树模板题. #include<cstdio> #include<cstring> #include<algorithm> #include<cs ...
- HDU 3473 Minimum Sum 划分树,数据结构 难度:1
http://acm.hdu.edu.cn/showproblem.php?pid=3473 划分树模板题目,需要注意的是划分树的k是由1开始的 划分树: 参考:http://blog.csdn.ne ...
- HDU 3473 Minimum Sum 划分树
题意: 给出一个长度为\(n(1 \leq n \leq 10^5)\)的序列\(a\) 有若干次查询l r:找到一个\(x\)使得\(\sum \limits_{l \leq i \leq r} \ ...
- [csu/coj 1080]划分树求区间前k大数和
题意:从某个区间内最多选择k个数,使得和最大 思路:首先题目给定的数有负数,如果区间前k大出现负数,那么负数不选和更大,于是对于所有最优选择,负数不会出现,所以用0取代负数,问题便转化为区间的前k大数 ...
- HDOJ题目4417 Super Mario(划分树求区间比k小的个数+二分)
Super Mario Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tota ...
- [poj2104]kth-number(归并树求区间第k大)
复杂度:$O(nlog^3n)$ #include<cstdio> #include<cstring> #include<algorithm> #include&l ...
- poj 2104 主席树(区间第k大)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 44940 Accepted: 14946 Ca ...
- POJ2761---Feed the dogs (Treap求区间第k大)
题意 就是求区间第k大,区间 不互相包含. 尝试用treap解决一下 第k大的问题. #include <set> #include <map> #include <cm ...
- HDU 3473 Minimum Sum (划分树)
题意:给定一个数组,有Q次的询问,每次询问的格式为(l,r),表示求区间中一个数x,使得sum = sigma|x - xi|最小(i在[l,r]之间),输出最小的sum. 思路:本题一定是要O(nl ...
随机推荐
- js获取滚动条的位置
页面具有 DTD,或者说指定了 DOCTYPE 时,使用 document.documentElement. 页面不具有 DTD,或者说没有指定了 DOCTYPE,时,使用 document.body ...
- python系列二:python3基本数据类型
#标准数据类型——number(数字)a, b, c = 1, 2.2, "hello"print(a, end = ", ")print(b, end = & ...
- 2015-02-08——js笔记
示例1: 关于事件对象 MSIE:window.event, cancelBubble, returnValue, srcElement, button(鼠标按键,1,4,2,左中右) W3C: ...
- 常用代码块:java使用剪贴板复制文本
// 获得系统剪切板 Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); // 复制到剪切板上 String ...
- rpm命令相关命令运用实例
1) 挂载光盘文件到/media目录 2) 进去/media目录下的Packages目录 3) 查看系统已安装的所有rpm包 4) 查看系统是否安装dhcp软件包 5,安装dhcp软件包 6) 查看d ...
- ThreadPoolExecutor 线程池任务队列分析 与 利特尔法则(Little's law)
一. 演示 public class ThreadPoolTest { static class MyThread implements Runnable { private String name; ...
- Python __setitem__()、__getitem__()、__delitem__()
转载:http://blog.csdn.net/xhw88398569/article/details/48690163 __xxxitem__:使用 [''] 的方式操作属性时被调用 __setit ...
- app是什么意思?智能手机的第三方应用程序
APP,在手机中的意思就是application的简称,也就是应用程序的意思,一般指手机软件,是安装在手机上的软件,完善原始系统的不足与个性化.APP是智能手机的第三方应用程序,app通常分为个人用户 ...
- 鸟哥的Linux私房菜-第一部分-第3章主机规划与磁盘分区
1. 选择一个与你的Linux搭配的主机配置 NAT服务器:小型企业或者学校都基本是只有一条对外的线路,网卡 SAMBA服务器:完成Windows网上邻居的功能,网卡和硬盘要求高 Mail服务器:如果 ...
- 剑指offer 面试17题
面试17题: 题目:打印从1到最大的n位数 题:输入数字n,按顺序打印出从1到最大的n位十进制数,比如输入3,则打印出1.2.3一直到最大的3位数999. 解题思路:需要考虑大数问题,这是题目设置的陷 ...