学习计划——整体二分

整体二分

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

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

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

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

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

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

  • 题目链接: https://www.luogu.com.cn/problem/P3834
  • 解题思路:
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;

}

  • 题目链接: https://codeforces.com/contest/1039/problem/D
  • 解题思路: 本题先考虑 O ( n 2 ) O(n^2) O(n2)如何去做,我们可以枚举长度 x x x然后自底向上贪心的去处理。对于每一个 x x x对应答案这个复杂度我们不好优化,于是我们考虑是否可以优化 x x x,我们发现 x x x对应的答案存在单调性,于是我们使用整体二分优化枚举
const int N = 2e5 + 5;
int n, ans[N], cnt;
vector <int> edge[N];
int dp[N];
void dfs (int u ,int fa, int k)
{
    dp[u] = 0;
    int mx1 = 0 , mx2 = 0;
    for (auto v : edge[u])
    {
        if (v != fa)
        {
            dfs (v, u, k);
            if (dp[v] > mx1) mx2 = mx1, mx1 = dp[v];
            else mx2 = max(mx2, dp[v]);
        }
    }
    if (mx1 + mx2 + 1 >= k) dp[u] = 0, cnt ++;
    else dp[u] = mx1 + 1;
}
void solve (int l , int r, int L , int R)
{
    if (l > r || L > R) return ;
    if (L == R)
    {
        for (int i = l ; i <= r ; i ++)
            ans[i] = L;
        return ;
    }
    cnt = 0;
    int mid = (l + r) >> 1;
    dfs (1, 0 , mid);
    ans[mid] = cnt;
    solve (l, mid-1, cnt, R);
    solve (mid+1, r, L, cnt);
}
int main ()
{
    CLOSE;
    cin >> n;
    for (int i = 1 ; i < n ; i ++)
    {
        int u , v;
        cin >> u >> v;
        edge[u].pb (v);
        edge[v].pb (u);
    }
    solve (1, n, 0, n);
    for (int i = 1 ; i <= n ; i ++)
        cout << ans[i] << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值