Educational Codeforces Round 81 (Rated for Div. 2)F(线段树)

预处理把左集划分为大小为1~i-1时,把全部元素都移动到右集的代价,记作sum[i]。

然后枚举终态时左集的大小,更新把元素i 留在/移动到 左集的代价。

树状数组/线段树处理区间修改/区间查询

 1 #define HAVE_STRUCT_TIMESPEC
 2 #include<bits/stdc++.h>
 3 using namespace std;
 4 #define ll long long
 5 const int N=2e5+7;
 6 struct Tree{
 7     ll minn,lazy;
 8 }tree[N<<2];
 9 ll sum[N];//前缀和
10 inline void build(int root,int l,int r){
11     if(l==r){
12         tree[root].minn=sum[l];//1~l的a[i]之和
13         tree[root].lazy=0;
14         return;
15     }
16     int mid=(l+r)>>1;
17     build((root<<1),l,mid);
18     build((root<<1|1),mid+1,r);
19     tree[root].minn=min(tree[(root<<1)].minn,tree[(root<<1|1)].minn);//up
20     return;
21 }
22 inline void pushdown(int root){
23     if(!tree[root].lazy)
24         return;
25     tree[(root<<1)].minn+=tree[root].lazy;
26     tree[(root<<1|1)].minn+=tree[root].lazy;
27     tree[(root<<1)].lazy+=tree[root].lazy;
28     tree[(root<<1|1)].lazy+=tree[root].lazy;
29     tree[root].lazy=0;
30     return;
31 }
32 inline void change(int root,int l,int r,int x,int y,int val){
33     if(r<x||l>y)
34         return;
35     if(x<=l&&r<=y){
36         tree[root].minn+=val;
37         tree[root].lazy+=val;
38         return;
39     }
40     int mid=(l+r)>>1;
41     pushdown(root);
42     change((root<<1),l,mid,x,y,val);
43     change((root<<1|1),mid+1,r,x,y,val);
44     tree[root].minn=min(tree[(root<<1)].minn,tree[(root<<1|1)].minn);//up
45     return;
46 }
47 int n,p[N],a[N],pos[N];
48 ll ans;
49 int main(){
50     ios::sync_with_stdio(false);
51     cin.tie(NULL);
52     cout.tie(NULL);
53     cin>>n;
54     for(int i=1;i<=n;++i){
55         cin>>p[i];
56         pos[p[i]]=i;//数字p[i]出现的位置为i
57     }
58     for(int i=1;i<=n;++i){
59         cin>>a[i];
60         sum[i]=sum[i-1]+a[i];//sum[i]为左集合大小为i,把左集合所有元素都移动到右集合的花费
61     }
62     build(1,1,n-1);
63     ans=min(a[1],a[n]);//a[1]为左集为空,a[n]为右集为空
64     for(int i=1;i<n;++i){//枚举左集大小,定下大小后,集合内元素也被定为1~i
65         change(1,1,n-1,1,pos[i]-1,a[pos[i]]);//找到元素i出现的位置,在它出现位置左边的sum[i]分别加上把元素i从右集合移动到左集合的代价(原本的sum[1~i-1]为把原本处于位置1~i-1的元素都移动到右边,此时加上元素1~i从右移动到左的代价)
66         change(1,1,n-1,pos[i],n,-a[pos[i]]);//在它出现位置及其右边的sum[i]分别减去把元素i从左集合移动到右集合的代价(元素i无需移动,可是移动的代价事先已经加到sum[i~n]里了)
67         ans=min(ans,tree[1].minn);//如果左集大小为i的代价最小就更新最小值
68     }
69     cout<<ans;
70     return 0;
71 }

原文地址:https://www.cnblogs.com/ldudxy/p/12244494.html

时间: 2024-11-07 08:01:57

Educational Codeforces Round 81 (Rated for Div. 2)F(线段树)的相关文章

Educational Codeforces Round 61 (Rated for Div. 2) G(线段树,单调栈)

#include<bits/stdc++.h>using namespace std;int st[1000007];int top;int s[1000007],t[1000007];int mx[4000007];int sum[4000007];int head[1000007],to[2000007],nex[2000007];int n,k;int a[10000077];int dfn;int tot;void pushup(int rt){    mx[rt]=max(mx[rt

Educational Codeforces Round 81 (Rated for Div. 2) C. Obtain The String

题目链接:http://codeforces.com/contest/1295/problem/C 题目:给定字符串s,t.  给定一个空串z,需要按照规则把z构造成 string z == string t 的字符串. 规则:有限次从s中任取子序列p,然后进行 string z += string p的操作, s不变. 问能不能构造出p,不能输出-1,可以得话最少几次可以构造出. 大致的想法就是n倍的s字符串串联,然后剔除不必要的字符,就可以得出z, 求最少的倍数n是多少. 主要思路就是用二分

Educational Codeforces Round 81 (Rated for Div. 2) B. Infinite Prefixes

题目链接:http://codeforces.com/contest/1295/problem/B 题目:给定由0,1组成的字符串s,长度为n,定义t = sssssss.....一个无限长的字符串. 题目定义一个平衡值x,取t的任意前缀Q,如果Q满足cnt(0,q) - cnt(1,q) = x,即Q中0 的个数-1的个数= x,说明当前的Q是满足题意得一个前缀,问满足x的前缀有多少个, 如果x = ∞,则输出-1. input 6 10 010010 题目给定说q的长度为28,30,32是平

【Educational Codeforces Round 81 (Rated for Div. 2) A】Display The Number

题目链接 [题解] 优先用2个棒子来凑1. 如果为奇数的话,多出来一根用3根来凑个7放在开头 [代码] #include <bits/stdc++.h> using namespace std; int main(){ #ifdef LOCAL_DEFINE freopen("E:\\rush.txt","r",stdin); #endif // LOCAL_DEFINE ios::sync_with_stdio(0),cin.tie(0); int T

Educational Codeforces Round 81 (Rated for Div. 2)

A - Display The Number 题意:给n根火柴,拼出最大的数字. 题解:肯定是数字越多越大,所以尽可能多拿最便宜的2根火柴一个"1",多余的肯定是拿一个"7",由于n>=2,没有特例. void test_case() { int n; scanf("%d", &n); if(n % 2 == 1) { printf("%d", 7); n -= 3; } while(n) { printf(&q

【Educational Codeforces Round 81 (Rated for Div. 2) C】Obtain The String

题目链接 [题解] 显然我们得按顺序获得目标t的每个字符. 对于t[0],t[1],t[2],t[3]... 我们可以在s中找到这么一个子序列. 显然如果找到尾巴还是没有需要的t[i]. 就得从s[0]开始重新开始顺序找. (然后答案递增,因为表示要重新开始加一个子序列了) 但是如果这么直接找的话,复杂度是O(|s||t|)的 是无法接受的. 所以我们可以另外开一个数组 next[i][j] 表示在i-1位置,如果要找下一个紧接着的j的话,需要到哪个位置找.(这个next数组整体往左偏移了下,便

【Educational Codeforces Round 81 (Rated for Div. 2) B】Infinite Prefixes

题目链接 [题解] 把0看成是1,把1看成是-1 求一个前缀和. pre[i] = pre[i-1]+1 得到delta = pre[n] 显然对于每个位置的值pre[i] 再复制一遍s的话. 下一个s的该位置,也即i+n的前缀和显然为pre[i]+delata 那么无限的情况就很显然了. 即pre[i]==x,而且delata==0. 只要出现一个这种情况,就是无限. 其他情况,每个位置都会朝着目标远离或者毕竟. 看看差值不是不是delta的整数倍就可以了. 如果是的话,说明可以变成x [代码

Educational Codeforces Round 81 (Rated for Div. 2) A Display The Number

A. Display The Number time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output You have a large electronic screen which can display up to 998244353998244353 decimal digits. The digits are displayed

Educational Codeforces Round 47 (Rated for Div. 2)F. Dominant Indices 线段树合并

题意:有一棵树,对于每个点求子树中离他深度最多的深度是多少, 题解:线段树合并快如闪电,每个节点开一个权值线段树,递归时合并即可,然后维护区间最多的是哪个权值,到x的深度就是到根的深度减去x到根的深度复杂度O(nlogn) //#pragma comment(linker, "/stack:200000000") //#pragma GCC optimize("Ofast,no-stack-protector") //#pragma GCC target("