zoukankan      html  css  js  c++  java
  • [CF1295E] Permutation Separation

    Description

    给定一个长度为 (n) 的排列,你可以将它切成两段 (A,B),分别作为两个集合,对于第 (i) 个元素,可以花费 (a[i]) 的代价把它移动到对面的集合中。求至少花费多少的代价,才能使得一个集合中的任意元素比另一个集合中的任意元素小。

    Solution

    枚举初态分界点 (pos) 和分界值 (val),设此时的答案为 (f(pos,lim)),暴力计算的话复杂度为 (O(n^2))

    考虑到 (f(pos,lim)-f(pos-1,lim)=sum_{lim < p_{pos}} a_{pos} - sum_{lim ge p_{pos}} a_{pos}),我们用线段树来维护对于某个确定的 (pos) 的所有 (f(pos,lim)),每次修改 (pos) 时,只需要将 (1 le lim < p_{pos}) 部分 (+a_{pos}),将 (p_{pos} le lim le n) 部分 (-a_{pos})。区间修改,区间询问最小值。

    特别注意,lim 是可以 =0 的。

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long 
    const int N = 1000005;
    
    struct SegmentTree 
    {
        int a[N],tag[N];
        void Pushup(int p)
        {
            a[p]=min(a[p*2],a[p*2+1]);
        }
        void Put(int p,int val)
        {
            a[p]+=val;
            tag[p]+=val;
        }
        void Pushdown(int p)
        {
            if(tag[p])
            {
                Put(p*2,tag[p]);
                Put(p*2+1,tag[p]);
                tag[p]=0;
            }
        }
        void Modify(int p,int l,int r,int ql,int qr,int val)
        {
            if(l>qr||r<ql) return;
            if(l>=ql&&r<=qr)
            {
                Put(p,val);
            }
            else 
            {
                Pushdown(p);
                Modify(p*2,l,(l+r)/2,ql,qr,val);
                Modify(p*2+1,(l+r)/2+1,r,ql,qr,val);
                Pushup(p);
            }
        }
        int Query()
        {
            return a[1];
        }
    } seg;
    
    int n,a[N],b[N],p[N],f[N];
    
    signed main()
    {
        ios::sync_with_stdio(false);
    
        cin>>n;
        for(int i=1;i<=n;i++) cin>>p[i];
        for(int i=1;i<=n;i++) cin>>a[i];
    
        for(int i=1;i<=n;i++) 
        {
            // cerr<<"Modify "<<p[i]<<" "<<n<<" "<<a[i]<<endl;
            seg.Modify(1,0,n,p[i],n,a[i]);
        }
        int ans=1e18;
        for(int i=1;i<n;i++)
        {
            seg.Modify(1,0,n,0,p[i]-1,a[i]);
            seg.Modify(1,0,n,p[i],n,-a[i]);
            ans=min(ans,seg.Query());
        }
        cout<<ans<<endl;
    }
    
    
  • 相关阅读:
    LeetCode 79. 单词搜索
    LeetCode 1143. 最长公共子序列
    LeetCode 55. 跳跃游戏
    LeetCode 48. 旋转图像
    LeetCode 93. 复原 IP 地址
    LeetCode 456. 132模式
    LeetCode 341. 扁平化嵌套列表迭代器
    LeetCode 73. 矩阵置零
    LeetCode 47. 全排列 II
    LeetCode 46. 全排列
  • 原文地址:https://www.cnblogs.com/mollnn/p/14037993.html
Copyright © 2011-2022 走看看