ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF1295E Permutation Separation

2020-01-30 22:57:16  阅读:312  来源: 互联网

标签:int sum tree pos Separation Permutation 序列 root CF1295E


我的blog

题目链接:CF1295E Permutation Separation

\[preface\]
开一波E题闷声发大财

感谢@Karry5307 在考后提供思路

\[description\]

给定一个序列\(p\)(为1~n的排列),和这个序列每一个数所对应的花费a以及序列的长度n。

取一数\(1\leq k<n\),将\(p\)序列分成两个序列,分别是\(p_1,p_2,...,p_k\)和\(p_{k+1},p_{k+2},...,p_n\)

将两个序列的某些数移到另一个序列使得第一个序列的所有数小于第二个序列的所有数,注意如果其中一组为空,则满足此条件,移动\(p_i\)的花费是\(a_i\)

求最小花费
\[solution\]
一道裸的线段树

考虑维护\(a_i\)的前缀和\(sum_i=\sum_{j=1}^{i}a_i\),因为\(1\leq k<n\),所以前缀和\(sum\)最多只要维护到\(a_{n-1}\)即可

假设第一个序列的所有数都移到了第二个序列值最小虽然不大可能
答案是\(sum\)中的最小值

因为\(p\)序列是1~n的排列,所以记\(pos_i\)为\(i\)在序列\(p\)中出现的位置

枚举i从1~n

假设将\(p[pos_i]\)最终在第一序列,那么\(p[pos_1],p[pos_2],...,,p[pos_{i-1}]一定在最终在第一序列\),考虑当前对前缀和的修改。

当\(k>=pos_i\)时,\(p[pos_i]\)在第一序列,那么不需要费用

当\(k<pos_i\)时,\(p[pos_i]\)在第二序列,需要\(a[pos_i]\)的费用移动到第一序列

则将\(sum_1\)~\(sum_{pos_i-1}\)的值分别加上\(a[pos_i]\)

\(sum_{pos_i}\)~\(sum_{n-1}\)的值分别减去\(a[pos_i]\)

当前策略最小值即当前\(sum\)的最小值。

答案即是对所有策略的最小值取最小值

\[code\]

#include <cstdio>
#include <algorithm>
#define re register
#define ll long long
#define lc (root<<1)
#define rc (root<<1|1)
using namespace std;
template<typename T>
inline void read(T&x)
{
    x=0;
    char s=(char)getchar();
    bool flag=false;
    while(!(s>='0'&&s<='9'))
    {
        if(s=='-')
            flag=true;
        s=(char)getchar();
    }
    while(s>='0'&&s<='9')
    {
        x=(x<<1)+(x<<3)+s-'0';
        s=(char)getchar();
    }
    if(flag)
        x=(~x)+1;
    return;
}
const int N=2e5+5;
struct Tree
{
    ll minn,lazy;
} tree[N<<2];
ll sum[N];
inline void build(int root,int l,int r)
{
    if(l==r)
    {
        tree[root].minn=sum[l];
        tree[root].lazy=0;
        return;
    }
    int mid=(l+r)>>1;
    build(lc,l,mid);
    build(rc,mid+1,r);
    tree[root].minn=min(tree[lc].minn,tree[rc].minn);
    return;
}
inline void pushdown(int root)
{
    if(!tree[root].lazy)
        return;
    tree[lc].minn+=tree[root].lazy;
    tree[rc].minn+=tree[root].lazy;
    tree[lc].lazy+=tree[root].lazy;
    tree[rc].lazy+=tree[root].lazy;
    tree[root].lazy=0;
    return;
}
inline void change(int root,int l,int r,int x,int y,int val)
{
    if(r<x||l>y)
        return;
    if(x<=l&&r<=y)
    {
        tree[root].minn+=val;
        tree[root].lazy+=val;
        return;
    }
    int mid=(l+r)>>1;
    pushdown(root);
    change(lc,l,mid,x,y,val);
    change(rc,mid+1,r,x,y,val);
    tree[root].minn=min(tree[lc].minn,tree[rc].minn);
    return;
}
int n,p[N],a[N],pos[N];
ll ans;
int main()
{
    read(n);
    for(re int i=1; i<=n; ++i)
    {
        read(p[i]);
        pos[p[i]]=i;
    }
    for(re int i=1; i<=n; ++i)
    {
        read(a[i]);
        sum[i]=sum[i-1]+a[i];
    }
    build(1,1,n-1);
    ans=tree[1].minn;
    for(re int i=1; i<=n; ++i)
    {
        change(1,1,n-1,1,pos[i]-1,a[pos[i]]);
        change(1,1,n-1,pos[i],n-1,-a[pos[i]]);
//      printf("%d\n",ans);
        ans=min(ans,tree[1].minn);
    }
    printf("%lld\n",ans);
    return 0;
}

标签:int,sum,tree,pos,Separation,Permutation,序列,root,CF1295E
来源: https://www.cnblogs.com/wangjunrui/p/12244238.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有