静态区间第k小 - 整体二分

蒟蒻终于学会整体二分啦!

思路

实现

丑陋无比的代码

#include <bits/stdc++.h>
using namespace std;

const int N = 200005;
int ar[N];
int lowbit(int t) { return t & (-t); }
void add(int i, int v) {
    for (; i < N; ar[i] += v, i += lowbit(i));
}
int sum(int i) {
    int s = 0;
    for (; i > 0; s += ar[i], i -= lowbit(i));
    return s;
}

struct Elem {
    int pos,val;
    bool operator < (const Elem &b) {
        return val < b.val;
    }
} e[200005];

struct Query {
    int l,r,k,ans;
} q[200005];

int n,m,a[200005];

void solve(int l,int r,vector<int> num,vector <int> v) {
    //cout<<l<<" "<<r<<" "<<num.size()<<" "<<v.size()<<endl;
    if(l==r) {
        for(int i=0;i<v.size();i++) {
            q[v[i]].ans = l;
        }
    }
    else {
        memset(ar,0,sizeof ar);
        vector <int> v1,v2,n1,n2;
        int mid = (l+r)>>1;
        for(int i=0;i<num.size();i++) {
            if(e[num[i]].val<=mid) {
                add(e[num[i]].pos,1);
                n1.push_back(num[i]);
            }
            else {
                n2.push_back(num[i]);
            }
        }
        for(int i=0;i<v.size();i++) {
            if(sum(q[v[i]].r)-sum(q[v[i]].l-1) >= q[v[i]].k) {
                v1.push_back(v[i]);
            }
            else {
                q[v[i]].k -= sum(q[v[i]].r)-sum(q[v[i]].l-1);
                v2.push_back(v[i]);
            }
        }
        if(v1.size()) solve(l,mid,n1,v1);
        if(v2.size()) solve(mid+1,r,n2,v2);
    }
}

int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        e[i].pos=i;
        e[i].val=a[i];
    }
    sort(e+1,e+n+1);
    for(int i=1;i<=m;i++) {
        scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);
    }
    vector <int> tmp;
    vector <int> num;
    for(int i=1;i<=n;i++) {
        num.push_back(i);
    }
    for(int i=1;i<=m;i++) {
        tmp.push_back(i);
    }
    solve(-1e+9,1e+9,num,tmp);
    for(int i=1;i<=m;i++) {
        cout<<q[i].ans<<endl;
    }
}

原文地址:https://www.cnblogs.com/mollnn/p/12273409.html

时间: 2024-07-31 10:48:53

静态区间第k小 - 整体二分的相关文章

【XSY2720】区间第k小 整体二分 可持久化线段树

题目描述 给你你个序列,每次求区间第\(k\)小的数. 本题中,如果一个数在询问区间中出现了超过\(w\)次,那么就把这个数视为\(n\). 强制在线. \(n\leq 100000,a_i<n,w\leq n\) 题解 考虑整体二分. 先看看离线要怎么做. 现在我们要计算每个数对每个区间的贡献. 对于每个询问区间和每种数,让这个区间最右边\(w\)个数对这个询问的贡献为\(1\),第\(w+1\)个数对这个询问的贡献为\(-w\). 这样每个数的贡献就是二维平面上的一个矩形.可以用扫描线+线段

[POJ2761]Feed the dogs(静态区间第k小,主席树)

题目链接:http://poj.org/problem?id=2761 题意:如题 主席树只能用模版,好菜. 1 /* 2 ━━━━━┒ギリギリ♂ eye! 3 ┓┏┓┏┓┃キリキリ♂ mind! 4 ┛┗┛┗┛┃\○/ 5 ┓┏┓┏┓┃ / 6 ┛┗┛┗┛┃ノ) 7 ┓┏┓┏┓┃ 8 ┛┗┛┗┛┃ 9 ┓┏┓┏┓┃ 10 ┛┗┛┗┛┃ 11 ┓┏┓┏┓┃ 12 ┛┗┛┗┛┃ 13 ┓┏┓┏┓┃ 14 ┃┃┃┃┃┃ 15 ┻┻┻┻┻┻ 16 */ 17 #include <algorithm>

洛谷.3834.[模板]可持久化线段树(主席树 静态区间第k小)

题目链接 //离散化后范围1~cnt不要错 #include<cstdio> #include<cctype> #include<algorithm> //#define gc() getchar() #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) const int N=2e5+5,MAXIN=2e6; int n,m,A[N],ref[N],cn

HDU 2665.Kth number 区间第K小

Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11394    Accepted Submission(s): 3465 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The f

poj 2104主席树求区间第k小

POJ - 2104 题意:求区间第k小 思路:无修改主席树 AC代码: #include "iostream" #include "iomanip" #include "string.h" #include "stack" #include "queue" #include "string" #include "vector" #include "set&

HDU3473--Minimum Sum(静态区间第k大)

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

POJ2104 区间第k小

题意就是区间第k大…… 题解: 前段时间用主席树搞掉了…… 如今看到划分树,是在想来写一遍,结果18号对着学长的代码调了一上午连样例都没过,好桑心…… 今天在做NOI2010超级钢琴,忽然发现用划分树很直观,果断决定再战划分树 对着网上的c++代码抄了一遍,A了,可是这编程复杂度有点高,忽然又看见盾哥的代码 很简短,和我原先的代码差不多,他怎么能A了呢……(后来发现区间第k小,我却写的第k大……sb啊) 考虑到盾哥的程序用到了离散化,因此没有考虑存在两个数相等的情况,这样就使代码减少很多 我报着

少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小

少年,想学带修改主席树吗 | BZOJ1901 带修改区间第k小 有一道题(BZOJ 1901)是这样的:n个数,m个询问,询问有两种:修改某个数/询问区间第k小. 不带修改的区间第k小用主席树很好写,不会的同学可以看一下这个. 加上修改怎么做呢?我们可以用数学老师成天讲的类比思想: 可以发现,不修改的区间k小问题中,每加入一个原序列中的数,对应的主席树在上一个的基础上进行修改,而查询的时候用右端点主席树减去左端点左边的主席树.这样的操作就像是维护前缀和:每次加入一个元素的时候,sum[i] =

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

前言 如果要求一些数中的第k大值,怎么做? 可以先就这些数离散化,用线段树记录每个数字出现了多少次. ... 那么考虑用类似的方法来求静态区间第k大. 原理 假设现在要有一些数 我们可以对于每个数都建一棵新的线段树,用来记录出现每个数字出现了多少次的前缀和. 那么假设要求区间[l,r]的第k大,将第r棵线段树减去第l-1棵线段树,像上面求所有数的第k大一样来求就可以了. 但是,对于每一个数都建一个线段树显然会爆空间. 现在考虑如何节约空间. 假设现在有四个数1 4 2 3,依次加入,可以这样处理