Minimum Sum

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3047    Accepted Submission(s): 701

Problem Description
You are given N positive integers, denoted as x0, x1 ... xN-1. Then give you some intervals [l, r]. For each interval, you need to find a number x to make as small as possible!
 
Input
The first line is an integer T (T <= 10), indicating the number of test cases. For each test case, an integer N (1 <= N <= 100,000) comes first. Then comes N positive integers x (1 <= x <= 1,000, 000,000) in the next line. Finally, comes an integer Q (1 <= Q <= 100,000), indicting there are Q queries. Each query consists of two integers l, r (0 <= l <= r < N), meaning the interval you should deal with.

 
Output
For the k-th test case, first output “Case #k:” in a separate line. Then output Q lines, each line is the minimum value of  . Output a blank line after every test case.
 
Sample Input
2
5
3 6 2 2 4
2
1 4
0 2
2
7 7
2
0 1
1 1
 
Sample Output
Case #1:
6
4
 
 
Case #2:
0
0
 

区间第k大的题目一般两种做法,,划分树 主席树,不过貌似划分树只支持静态区间第k大。

这道题由于内存限制 只能用划分树。。具体就是 先找出区间[l,r]内的中位数,(为什么是中位数,大白书貌似有介绍),然后直接求和。

MLE到死啊,,注释memset部分之后就过了,不知道为什么
划分树代码:

 #include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const double eps = 1e-;
const int maxn = ;
int sorted[maxn],tree[][maxn],toleft[][maxn]; //toleft[dep][i]表示第dep层1-i中进入左子树元素的个数
ll leftsum[][maxn], sum[maxn]; //leftsum[dep][i]表示第dep层1-i中进入左子树元素的和 void build (int l,int r,int dep)
{
if (l == r)
return;
int mid = (l + r) >> ;
int same = mid - l + ;
for (int i = l; i <= r; i++)
if (tree[dep][i] < sorted[mid])
same--;
int lpos = l,rpos = mid + ;
for (int i = l; i <= r; i++)
{
if (tree[dep][i] < sorted[mid])
{
tree[dep+][lpos++] = tree[dep][i];
leftsum[dep][i] = leftsum[dep][i-] + tree[dep][i];
}
else if (tree[dep][i] == sorted[mid] && same > )
{
tree[dep+][lpos++] = tree[dep][i];
leftsum[dep][i] = leftsum[dep][i-] + tree[dep][i];
same--;
}
else
{
tree[dep+][rpos++] = tree[dep][i];
leftsum[dep][i] = leftsum[dep][i-];
}
toleft[dep][i] = toleft[dep][l-] + lpos - l;
}
build (l,mid,dep+);
build (mid+,r,dep+);
}
int lnum,rnum;
ll lsum,rsum;
int query(int l,int r,int dep,int ua,int ub,int k)
{
if (ua == ub)
return tree[dep][ua];
int mid = (l + r) >> ;
int cnt = toleft[dep][ub] - toleft[dep][ua-];
if (cnt >= k)
{
int newl = l + toleft[dep][ua-] - toleft[dep][l-];
int newr = newl + cnt - ;
return query(l,mid,dep+,newl,newr,k);
}
else
{
int newr = ub + toleft[dep][r] - toleft[dep][ub];
int newl = newr - (ub - ua - cnt);
lnum += cnt;
lsum += leftsum[dep][ub] - leftsum[dep][ua-];
return query(mid+,r,dep+,newl,newr,k-cnt);
}
} int main(void)
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
#endif
int T, cas = ;
scanf ("%d",&T);
while (T--)
{
int n,m;
scanf ("%d",&n);
sum[] = ;
for (int i = ; i <= n; i++)
{
scanf ("%d",&tree[][i]);
sum[i] = sum[i-] + tree[][i];
sorted[i] = tree[][i];
}
sort(sorted+,sorted+n+);
build (,n,);
scanf ("%d",&m);
printf ("Case #%d:\n",cas++);
while (m--)
{
int u, v;
scanf ("%d%d",&u,&v);
u++,v++;
lnum = ;
lsum = ;
int mid_num = query(,n,,u,v,(v-u)/+); //中位数
rnum = (v - u + - lnum); // u~v 区间内大于mid_num的个数
rsum = (sum[v] - sum[u-] - lsum); //u~v 区间内大于mid_num的数的和
ll ans = rsum - lsum + mid_num * (lnum - rnum);
printf("%I64d\n",ans);
}
printf("\n");
}
return ;
}

主席树部分代码:(主席树会MLE,已经和划分树代码对拍过,应该没问题)

 typedef long long ll;
const int maxn = 1e5+;
int n,q,tot; //主席树部分
int lson[maxn*],rson[maxn*],c[maxn*],tree[maxn]; ll sum[maxn*];
int build (int l,int r)
{
int root = tot++;
c[root] = ;
sum[root] = ;
if (l != r)
{
int mid = (l + r) >> ;
lson[root] = build(l,mid);
rson[root] = build(mid+,r);
}
return root;
}
int update(int root,int pos,int val,int k)
{
int newroot = tot++;
int tmp = newroot;
int l = , r = n;
c[newroot] = c[root] + val;
sum[newroot] = sum[root] + k;
while (l < r)
{
int mid = (l + r) >> ;
if (pos <= mid)
{
rson[newroot] = rson[root];
root = lson[root];
lson[newroot] = tot++;
newroot = lson[newroot];
r = mid;
}
else
{
lson[newroot] = lson[root];
root = rson[root];
rson[newroot] = tot++;
newroot = rson[newroot];
l = mid + ;
}
c[newroot] = c[root] + val;
sum[newroot] = sum[root] + k;
}
return tmp;
}
ll lsum,rsum; //lsum小于中位数的和,rsum大于中位数的和
ll query(int root,int l,int r,int ua,int ub) //查询1-root 大于ua小于ub的和
{
if (ub < ua)
return ;
if (ua <= l && ub >= r)
{
return sum[root];
}
int mid = (l + r) >> ;
ll t1 = ,t2 = ;
if (ua <= mid)
t1 = query(lson[root],l,mid,ua,ub);
if (ub > mid)
t2 = query(rson[root],mid+,r,ua,ub);
return t1 + t2;
}
int query1(int root,int l,int r,int ua,int ub) //查询1-root 在ua ub 之间的数的个数
{
if (ub < ua)
return ;
if (ua <= l && ub >= r)
{
return c[root];
}
int mid = (l + r) >> ;
int t1 = ,t2 = ;
if (ua <= mid)
t1 = query1(lson[root],l,mid,ua,ub);
if (ub > mid)
t2 = query1(rson[root],mid+,r,ua,ub);
return t1 + t2;
}
int query(int left,int right,int k) //查询left right区间第k大
{
int l_root = tree[left-];
int r_root = tree[right];
int l = , r = n;
while (l < r)
{
int mid = (l + r) >> ;
int tmp = c[lson[r_root]] - c[lson[l_root]];
if (tmp <= k)
{
k -= tmp;
r_root = rson[r_root];
l_root = rson[l_root];
l = mid + ;
}
else
{
l_root = lson[l_root];
r_root = lson[r_root];
r = mid;
}
}
return l;
}
int vec[maxn],rel[maxn],idx;
//离散化
inline void init_hash()
{
sort(vec,vec+idx);
idx = unique(vec,vec+idx) - vec;
}
inline int _hash(ll x)
{
return lower_bound(vec,vec+idx,x) - vec + ;
} int main(void)
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("wa.txt","w",stdout);
#endif
int t,cas = ;
scanf ("%d",&t);
while (t--)
{
memset(sum,,sizeof(sum));
scanf ("%d",&n);
idx = tot = ;
for (int i = ; i<= n; i++)
{
//scanf ("%d",a+i);
scanf ("%d",tree+i);
vec[idx++] = tree[i];
}
init_hash();
tree[] = build(,n);
for (int i = ; i <= n; i++)
{
int tmp = _hash(tree[i]);
rel[tmp] = tree[i]; tree[i] = update(tree[i-],tmp,,tree[i]);
//tree[i] = tmp2;
}
scanf ("%d",&q);
printf("Case #%d:\n",cas++);
while (q--)
{
int u,v;
scanf ("%d%d",&u,&v);
u++,v++;
int vir_mid = query(u,v,(v-u)/);
int mid_num = rel[vir_mid]; //中位数
lsum = query(tree[u-],,n,,vir_mid-);
rsum = query(tree[u-],,n,vir_mid+,n);
ll x1 = lsum, x2 = rsum; lsum = query(tree[v],,n,,vir_mid-);
rsum = query(tree[v],,n,vir_mid+,n);
int lnum = query1(tree[v],,n,,vir_mid - ) - query1(tree[u-],,n,,vir_mid - );
int rnum = query1(tree[v],,n,vir_mid + ,n) - query1(tree[u-],,n,vir_mid + ,n);
printf("%I64d\n",rsum - x2 - (lsum - x1) + (lnum - rnum) * mid_num);
}
printf("\n");
}
return ; }

HDU3473--Minimum Sum(静态区间第k大)的更多相关文章

  1. 可持久化线段树(主席树)——静态区间第k大

    主席树基本操作:静态区间第k大 #include<bits/stdc++.h> using namespace std; typedef long long LL; ,MAXN=2e5+, ...

  2. poj2104&&poj2761 (主席树&&划分树)主席树静态区间第k大模板

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 43315   Accepted: 14296 Ca ...

  3. 静态区间第k大(归并树)

    POJ 2104为例 思想: 利用归并排序的思想: 建树过程和归并排序类似,每个数列都是子树序列的合并与排序. 查询过程,如果所查询区间完全包含在当前区间中,则直接返回当前区间内小于所求数的元素个数, ...

  4. 主席树(静态区间第k大)

    前言 如果要求一些数中的第k大值,怎么做? 可以先就这些数离散化,用线段树记录每个数字出现了多少次. ... 那么考虑用类似的方法来求静态区间第k大. 原理 假设现在要有一些数 我们可以对于每个数都建 ...

  5. 主席树学习笔记(静态区间第k大)

    题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输出 ...

  6. 数据结构2 静态区间第K大/第K小

    给定数组$A[1...N]$, 区间$[L,R]$中第$K$大/小的数的指将$A[L...R]$中的数从大到小/从小到大排序后的第$K$个. "静态"指的是不带修改. 这个问题有多 ...

  7. POJ2104-- K-th Number(主席树静态区间第k大)

    [转载]一篇还算可以的文章,关于可持久化线段树http://finaltheory.info/?p=249 无修改的区间第K大 我们先考虑简化的问题:我们要询问整个区间内的第K大.这样我们对值域建线段 ...

  8. HDU 2665 Kth number(主席树静态区间第K大)题解

    题意:问你区间第k大是谁 思路:主席树就是可持久化线段树,他是由多个历史版本的权值线段树(不是普通线段树)组成的. 具体可以看q学姐的B站视频 代码: #include<cmath> #i ...

  9. poj2761静态区间第k大

    例题:poj2761 题目要求:给定一个长度为n的序列,给定m个询问,每次询问求[l,r]区间内的第k大: 对于这道题目来说,很多算法都可以使用,比如说树套树(一个负责划分区间,一个负责维护这段区间内 ...

随机推荐

  1. shell 中条件判断

    if 中的 -z 到 -d 的意思 2011-09-05 10:30 [ -a FILE ] 如果 FILE 存在则为真. [ -b FILE ] 如果 FILE 存在且是一个块特殊文件则为真. [  ...

  2. Drawable 着色的后向兼容方案

    看到 Android Weekly 最新一期有一篇文章:Tinting drawables,使用 ColorFilter 手动打造了一个TintBitmapDrawable,之前也看到有些文章使用这种 ...

  3. C#关于使用枚举遇到的问题----Parse()方法使用注意

    声明了一个枚举 public enum ceshimeiju { 跃动,光子} ceshimeiju ce = Enum.Parse(typeof(ceshimeiju ), "跃动&quo ...

  4. img图片元素下多余空白解决方案

    在进行页面的DIV+CSS排版时,遇到IE6(当然有时Firefox下也会偶遇)浏览器中的图片元素img下出现多余空白的问题绝对是常见的对於 该问题的解决方法也是「见机行事」,根据原因的不同要用不同的 ...

  5. 服务器端调用Word组件读取Word权限、未将对象引用到对象实例终极解决方案

    最近因为业务需要,需要在服务器上调用Word组件,结果遇到各种问题,比如检索 COM 类工厂中 CLSID 为 {000209FF-0000-0000-C000-000000000046} 的组件失败 ...

  6. phpmyadmin设置id自增(AUTO_INCREMENT)(转)

    phpmyadmin设置id自增(AUTO_INCREMENT)   在A_I 前面打勾:如图 AUTO_INCREMENT =A_I 查看效果  

  7. XML and JSON 验证

    function ChkJson(strJson) { //判断Json格式是否正确 if (strJson == null || strJson == "") return tr ...

  8. Objective-C学习篇08—NSDictionary与NSSet

    NSDictionary与NSMutableDictionary NSSet与NSMutableSte 字典 字典:字典分为可变字典NSDictionary和不可变字典NSMutableDiction ...

  9. (一)Angularjs - 入门

    AngularJS进行应用开发的一个重要的思维模式: 从构造声明式界面入手 ng-app: 这个指定定义并且关联了使用angularJS的HTML页面部分 ng-model: 这个指定定义并绑定Ang ...

  10. [转] linux 下 进程和线程的区别

    1.进程与线程 进程是程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集.从内核的观点看,进程的目的就是担当分配系统资源(CPU时间.内存等)的基本单位. 线程是进程的一个执行流,是C ...