整体二分学习笔记

  • 整体二分一般适用与可离线询问的问题,属于离线算法
  1. 可以使用整体二分解决的题目需要满足以下性质:

  2. 询问的答案具有可二分性

  3. 修改对判定答案的贡献互相独立 ,修改之间互不影响效果

  4. 修改如果对判定答案有贡献,则贡献为一确定的与判定标准无关的值

  5. 贡献满足交换律,结合律,具有可加性

  6. 题目允许使用离线算法

  • 经典问题:
  1. P3834,区间第k大
//#define LOCAL
#include 
using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define sz(a) (int)a.size()
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define LF putchar('\n')
#define SP putchar(' ')
#define p_queue priority_queue
#define CLOSE ios::sync_with_stdio(0); cin.tie(0)

template<typename T>
void read(T &x) {
     x = 0;char ch = getchar();ll f = 1;while(!isdigit(ch)){
     if(ch == '-')f *= -1;ch = getchar();}while(isdigit(ch)){
     x = x * 10 + ch - 48; ch = getchar();}x *= f;}
template<typename T, typename... Args>
void read(T &first, Args& ... args) {
     read(first);read(args...);}
template<typename T>
void write(T arg) {
     T x = arg;if(x < 0) {
     putchar('-'); x =- x;}if(x > 9) {
     write(x / 10);}putchar(x % 10 + '0');}
template<typename T, typename ... Ts>
void write(T arg, Ts ... args) {
     write(arg);if(sizeof...(args) != 0) {
     putchar(' ');write(args ...);}}
using namespace std;

ll gcd(ll a, ll b) {
     
    return b == 0 ? a : gcd(b, a % b);
}

ll lcm(ll a, ll b) {
     
    return a / gcd(a, b) * b;
}

const int N = 2e5 + 5;
int num[N];
int n , m;
struct node1
{
     
    int x, val;
};
struct node2 {
     
    int id , l , r , k;
};
int ans[N];
vector <node1> a;
vector <node2> q;
struct BIT
{
     
    int tree[N] ;
    void init()
    {
     
        mem(tree,0) ;
    }
    int lowbit(int k)
    {
     
        return k & -k;
    }
    void add(int x , int k)
    {
     
        while(x <= n)
        {
     
            tree[x] += k ;
            x += lowbit(x) ;
        }
    }
    int sum(int x)
    {
     
        int ans = 0 ;
        while(x != 0)
        {
     
            ans += tree[x] ;
            x -= lowbit(x) ;
        }
        return ans ;
    }
    int query(int l , int r)
    {
     
        return sum(r) - sum(l - 1) ;
    }
} bit ;
void solve (ll L, ll R, vector <node1> a, vector<node2> q)
{
     
    if (!a.size() || !q.size())
        return ;
    bit.init();
    ll mid = (L + R) >> 1;
    if (L == R)
    {
     
        for (auto v : q)
            ans[v.id] = L;
        return ;
    }
    vector<node1> a1, a2;
    vector<node2> q1, q2;
    for (auto v : a)
    {
     
        if (v.val <= mid)
            a1.pb(v), bit.add (v.x , 1);
        else
            a2.pb(v);
    }
    for (auto v : q)
    {
     
        int l = v.l , r = v.r, k = v.k;
        int t = bit.query(l, r);
        if (k <= t)
            q1.pb(v);
        else
            q2.pb({
     v.id,v.l,v.r,v.k - t});
    }
    solve (L, mid, a1, q1);
    solve (mid + 1 , R , a2, q2);
}
int main()
{
     
    read (n, m);
    for (int i = 1 ; i <= n ; i ++) {
     
        read(num[i]);
        a.pb ({
     i, num[i]});
    }
    for (int i = 1 ; i <= m ; i ++)
    {
     
        int l , r, k;
        read (l ,r , k);
        q.pb({
     i , l , r , k});
    }
    solve (-INF, INF, a, q);
    for (int i = 1 ; i <= n ; i ++)
        write (ans[i]), LF;

}

你可能感兴趣的:(二分)