• 整体二分学习笔记


    思路:

    ([l,r],[L,R]) 分别为答案的值域和定义域。整体二分的过程中像主席树一样按时间顺序存入数组分治:

    • 先找到当前答案与 (mid) 之间的关系,并分类。

    • 分好类,以其作为下一层分治的数组。

    例题:

    区间第k小:

    题目:Luogu P3834 【模板】可持久化线段树 2(主席树)

    离线整体二分一次即可。

    #include <cmath>
    #include <queue>
    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define ZYC using
    #define AK namespace
    #define IOI std
    #define ll long long
    
    ZYC AK IOI;
    
    const int N = 1e5 + 10, M = 5e4 + 10;
    
    inline ll Read()
    {
    	ll x = 0, f = 1;
    	char c = getchar();
    	while (c != '-' && (c < '0' || c > '9')) c = getchar();
    	if (c == '-') f = -f, c = getchar();
    	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
    	return x * f;
    }
    
    int n, m;
    ll t[N], ans[N];
    
    void modify(int x, ll val) {for (int i = x; i <= n; i += i & -i) t[i] += val;} 
    ll query(int x) {ll ans = 0;for (int i = x; i; i -= i & -i) ans += t[i]; return ans;} 
    
    struct node
    {
    	int x, y, k, id;
    }q[N + M], q1[N + M], q2[N + M];
    
    void Solve (ll l, ll r, int L, int R)
    {
    	if (l > r || L > R) return ; 
    	if(l == r)
    	{
    		for (int i = L; i <= R; i++) if(q[i].id) ans[q[i].id] = l;
    		return ;
    	}
    	ll mid = l + r >> 1;
    	int n1 = 0, n2 = 0;
    	for (int i = L; i <= R; i ++)
    		if (q[i].id) 
    		{
    			ll tmp = query(q[i].y) - query(q[i].x - 1);
    			if (q[i].k <= tmp) q1[++n1] = q[i];
    			else q[i].k -= tmp, q2[++n2] = q[i];
    		}
    		else
    			if (q[i].x <= mid) modify(q[i].y, 1), q1[++n1] = q[i];
    			else q2[++n2] = q[i];
    	for (int i = 1; i <= n1; i++) if(!q1[i].id) modify(q1[i].y, -1);
    	
    	for (int i = 1; i <= n1; i++) q[L + i - 1] = q1[i];
    	for (int i = 1; i <= n2; i++) q[L + n1 + i - 1] = q2[i];
    	
    	Solve(l, mid, L, L + n1 - 1), Solve(mid + 1, r, L + n1, R);
    }
    
    int main()
    {
    	n = Read(), m = Read();
    	for (int i = 1; i <= n; i++) q[i].x = Read(), q[i].y = i;
    	for (int i = 1; i <= m; i++) 
    		q[i + n].x = Read(), q[i + n].y = Read(), q[i + n].k = Read(), q[i + n].id = i;
    	Solve(-1e9, 1e9, 1, n + m);
    	for (int i = 1; i <= m; i++) printf ("%lld
    ", ans[i]);
    	return 0;
    }
    
    

    To be continued...

  • 相关阅读:
    第四周课下作业
    # 20165206 2017-2018-2 《Java程序设计》第4周学习总结
    20165206 2017-2018-2 《Java程序设计》第三周学习总结
    20165206 2017-2018-2 《Java程序设计》第二周学习总结
    第一周学习总结
    20165206 预备作业3 Linux安装及学习
    20165206学习基础和C语言基础调查
    20165206 我期望的师生关系
    channelartlist标签调用实例
    dede如何按自己写的ID进行排序
  • 原文地址:https://www.cnblogs.com/GJY-JURUO/p/14878082.html
Copyright © 2020-2023  润新知