hdu3437 划分树 区间内小于第K大的值得和

Minimum Sum

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

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

题意: 有n个元素的数组,有q次查询,对于每次询问,希望得到一个值x,使区间[L,R]内,  的值最小。

思路:

既然要让这个值最小,那么这个区间内的中位数一定满足。不过这里还要处理这个区间里面小于中位数的值得和。

这时候,可以在建树的时候同时处理。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<string>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define INF 1000000001
#define MOD 1000000007
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pi acos(-1.0)
using namespace std;
const int MAXN = 100010;
int num[20][MAXN],cnt[20][MAXN],sor[MAXN],n,leftnum;
ll sum[20][MAXN],leftsum,all[MAXN];//sum记录第d层 第i个数之前小于sor[m]的和
void build(int l,int r,int d)
{
    if(l == r){
        return ;
    }
    int m = (l + r) >> 1;
    int same_m = m - l + 1;
    for(int i = l; i <= r; i++){
        if(num[d][i] < sor[m])same_m --;
    }
    int cnt_small = 0;
    int pl,pr;
    ll val = 0;
    pl = l,pr = m + 1;
    for(int i = l; i <= r; i++){
        if(num[d][i] < sor[m]){
            cnt_small ++;
            val += num[d][i];
            sum[d][i] = val;
            cnt[d][i] = cnt_small;
            num[d+1][pl++] = num[d][i];
        }
        else if(num[d][i] == sor[m] && same_m){
            same_m --;
            cnt_small ++;
            val += num[d][i];
            sum[d][i] = val;
            cnt[d][i] = cnt_small;
            num[d+1][pl++] = num[d][i];
        }
        else {
            sum[d][i] = val;
            cnt[d][i] = cnt_small;
            num[d+1][pr++] = num[d][i];
        }
    }
    build(l,m,d+1);
    build(m+1,r,d+1);
}
ll query(int L,int R,int k,int l,int r,int d)
{
    if(l == r){
        return num[d][l];
    }
    int m = (l + r) >> 1;
    int s,ss;
    ll val = 0;
    if(l == L)s = 0, val = sum[d][R];
    else s = cnt[d][L-1], val = sum[d][R] - sum[d][L-1];
    ss = cnt[d][R] - s;
    if(ss >= k){
        int newl = l + s;
        int newr = l + s + ss - 1;
        return query(newl,newr,k,l,m,d+1);
    }
    else {
        leftnum += ss;//进入左孩子不用处理,进入右孩子时 就要加上左孩子的值
        leftsum += val;
        int a = L - l - s;
        int b = R - L + 1 - ss;
        int newl = m + 1 + a;
        int newr = m + 1 + a + b - 1;
        return query(newl,newr,k - ss,m+1,r,d+1);
    }
}
int main()
{
    int t,ff = 0;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        memset(all,0,sizeof(all));
        memset(num,0,sizeof(num));
        for(int i = 1; i <= n; i++){
            scanf("%d",&num[1][i]);
            sor[i] = num[1][i];
            all[i] = all[i-1] + sor[i];
        }
        sort(sor + 1,sor + n + 1);
        build(1,n,1);
        int q,x,y;
        scanf("%d",&q);
        printf("Case #%d:\n",++ff);
        while(q--){
            scanf("%d%d",&x,&y);
            x += 1;
            y += 1;
            int len = (y - x + 1);
            ll tp;
            leftnum = 0;
            leftsum = 0;
            if(len % 2){
                int k = (len + 1) >> 1;
                tp = query(x,y,k,1,n,1);
            }
            else {
                int k = len >> 1;
                tp = query(x,y,k,1,n,1);
            }
            //cout<<tp<<‘ ‘<<leftnum<<‘ ‘<<leftsum<<‘ ‘<<all[y]<<‘ ‘<<all[x+leftnum]<<endl;
            ll ans = tp * (leftnum + 1) - (leftsum + tp) + (all[y] - all[x - 1] - (leftsum + tp)) - (y - x + 1 - (leftnum + 1)) * tp;
            printf("%lld\n",ans);
        }
        printf("\n");
    }
    return 0;
}
时间: 2024-12-20 16:50:27

hdu3437 划分树 区间内小于第K大的值得和的相关文章

HDU5107---K-short Problem (线段树区间 合并、第k大)

题意:二维平面上 N 个高度为 Hi 建筑物,M次询问,每次询问输出 位于坐标(x ,y)左下角(也就是xi <= x && yi <= y)的建筑物中的第k高的建筑物的高度,如果不存在输出-1. 思路:可以发现k很小,最大才是10.对于区间第k大的问题,如果k很小的话,线段树也是可以的,,当然这里要用到 区间合并,对于每个节点 记录其 孩子中 前2*k个高度(不一定非要2*k,只要大于k就可以,至于为什么,自己可以想想),进行合并排序. 1 #include <cstd

poj2104 划分树 区间K大 在线 无修改

博主sbit....对于高级数据结构深感无力,然后这些东西在OI竟然烂大街了,不搞就整个人都不好了呢. 于是我勇猛的跳进了这个大坑 ——sbit 区间K大的裸题,在线,无修改. 可以用归并树(\(O(nlog^3n)\)),也可用划分树(\(O(nlogn + mlogn)\)).果断划分树...(以后再来看归并树...再来看...来看..看..) 划分树是个什么东西呢?为什么可以做区间k大呢? 想想平衡树做k大时是如何搞的,其实内在原理是一样的. 划分树分两个步骤:建树与询问,这两个步骤相互关

HDU 5249 离线树状数组求第k大+离散化

KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1160    Accepted Submission(s): 488 Problem Description 你工作以后, KPI 就是你的全部了. 我开发了一个服务,取得了很大的知名度.数十亿的请求被推到一个大管道后同时服务从管头拉取请求.让我们来定义每个请求都有一个重要值.我的

HDU 4417 (划分树+区间小于k统计)

题目链接:  http://acm.hdu.edu.cn/showproblem.php?pid=4417 题目大意:给定一个区间,以及一个k值,求该区间内小于等于k值的数的个数.注意区间是从0开始的. 解题思路: 首先这题线段树可以解.方法是维护一个区间最大值max,一个区间点个数s,如果k>max,则ans=s+Q(rson),否则ans=Q(lson). 然后也可以用求区间第K大的划分树来解决,在对原来求第K大的基础上改改就行,方法如下: Build方法同第K大. 对于Query: ①左区

HDU 4417 Super Mario(划分树问题求不大于k的数有多少)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3625    Accepted Submission(s): 1660 Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping ability

POJ2985 The k-th Largest Group[树状数组求第k大值 并查集]

The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8807   Accepted: 2875 Description Newman likes playing with cats. He possesses lots of cats in his home. Because the number of cats is really huge, Newman wants to g

hdu 2985 The k-th Largest Group 树状数组求第K大

The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8353   Accepted: 2712 Description Newman likes playing with cats. He possesses lots of cats in his home. Because the number of cats is really huge, Newman wants to g

zoj 3635 Cinema in Akiba (树状数组求第K大)

Cinema in Akiba Cinema in Akiba (CIA) is a small but very popular cinema in Akihabara. Every night the cinema is full of people. The layout of CIA is very interesting, as there is only one row so that every audience can enjoy the wonderful movies wit

#6279. 数列分块入门 3(询问区间内小于某个值 xx 的前驱(比其小的最大元素))

题目链接:https://loj.ac/problem/6279 题目大意:中文题目 具体思路:按照上一个题的模板改就行了,但是注意在整块查找的时候的下标问题. AC代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 # define ll long long 4 const int maxn = 2e5+100; 5 const int mod = 1e8+7; 6 const int inf = 0x3f3f3f3f; 7 ll l