ICode9

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

CF1295E Permutation Separation

2020-01-31 10:50:51  阅读:261  来源: 互联网

标签:lazy MIN int mid sh Separation Permutation 集合 CF1295E


线段树

难得把E想出来,写出来,但却没有调出来(再给我5分钟),我的紫名啊,我一场上紫的大好机会啊

 


 

首先考虑是否能将$k$在$1$--$n-1$的每一个的最小代价都求出来

因为$k$从$i$到$i-1$左右两边的集合只相差一个数,所以可以考虑递推

可以发现如果最终满足条件,那么左边集合的最大数一定为该集合当前的大小

且在每一个小于此大小的数都存在于左边这个集合中

由于给出的序列是一个排列,每一个数的范围是$1$--$n$

那么只要对于每一个k都进行枚举左边集合的大小计算代价,取最小值,就是该取该k时最小值

但直接暴力枚举的复杂度时$O(n^{2})$的

那么可以线段树维护以左边集合大小为每一个元素的序列

我们让$k$从$n-1$到$1$开始考虑递推

对于将$k$减一,左边集合只差了一个数

设这个数为$p$,代价为$v$

那么这个数对枚举左边集合大小的影响即是

集合大小为$p$-$n$的代价$+v$

集合大小为$0$-$p-1$的代价$-v$

然后线段树维护区间修改即可

 1 #include <bits/stdc++.h>
 2 #define m_k make_pair
 3 #define int long long
 4 #define inf (int)1e18
 5 using namespace std;
 6 const int N=2*1e5+100;
 7 int n,p[N],v[N],sum[N],ans;
 8 struct node
 9 {
10     int MIN,lazy;
11 }sh[N*4];
12 void pushup(int x)
13 {
14     sh[x].MIN=min(sh[x+x].MIN,sh[x+x+1].MIN);
15 }
16 void pushdown(int x)
17 {
18     int v=sh[x].lazy;
19     sh[x+x].lazy+=v;
20     sh[x+x].MIN+=v;
21     sh[x+x+1].lazy+=v;
22     sh[x+x+1].MIN+=v;
23     sh[x].lazy=0;
24 }
25 void build(int x,int l,int r)
26 {
27     if (l==r)
28     {
29         sh[x].lazy=0;
30         sh[x].MIN=sum[n]-sum[l];//此时将k取到n,所有元素都在左边集合
31         return;
32     }
33     int mid=(l+r)>>1;
34     build(x+x,l,mid);
35     build(x+x+1,mid+1,r);
36     pushup(x);
37 }
38 void change(int x,int l,int r,int L,int R,int v)//线段树维护区间修改
39 {
40     if (L<=l && R>=r)
41     {
42         sh[x].MIN+=v;
43         sh[x].lazy+=v;
44         return;
45     }
46     pushdown(x);
47     int mid=(l+r)>>1;
48     if (L<=mid) change(x+x,l,mid,L,R,v);
49     if (R>mid) change(x+x+1,mid+1,r,L,R,v);
50     pushup(x);
51 }
52 signed main()
53 {
54     scanf("%lld",&n);
55     for (int i=1;i<=n;i++)
56       scanf("%lld",&p[i]);
57     for (int i=1;i<=n;i++)
58     {
59         int a;
60         scanf("%lld",&a);
61         v[p[i]]=a;//记录每一个数值的代价
62     }
63     for (int i=1;i<=n;i++) sum[i]=sum[i-1]+v[i];//计算前缀和
64     build(1,0,n);
65     ans=inf;//由于k不能取到n,所有ans不进行计算,直接赋值为inf
66     for (int i=n;i>=2;i--)
67     {
68         change(1,0,n,p[i],n,v[p[i]]);//同上
69         change(1,0,n,0,p[i]-1,-v[p[i]]);
70         ans=min(ans,sh[1].MIN);
71     }
72     printf("%lld\n",ans);
73 }
View Code

 

标签:lazy,MIN,int,mid,sh,Separation,Permutation,集合,CF1295E
来源: https://www.cnblogs.com/huangchenyan/p/12244765.html

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

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

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

ICode9版权所有