[Educational Codeforces Round 81 (Rated for Div. 2)]E. Permutation Separation(线段树,思维,前缀和)
[Educational Codeforces Round 81 (Rated for Div. 2)]E. Permutation Separation(线段树,思维,前缀和)
E. Permutation Separation
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You are given a permutation p1,p2,…,pnp1,p2,…,pn (an array where each integer from 11 to nn appears exactly once). The weight of the ii-th element of this permutation is aiai.
At first, you separate your permutation into two non-empty sets — prefix and suffix. More formally, the first set contains elements p1,p2,…,pkp1,p2,…,pk, the second — pk+1,pk+2,…,pnpk+1,pk+2,…,pn, where 1≤k<n1≤k<n.
After that, you may move elements between sets. The operation you are allowed to do is to choose some element of the first set and move it to the second set, or vice versa (move from the second set to the first). You have to pay aiai dollars to move the element pipi.
Your goal is to make it so that each element of the first set is less than each element of the second set. Note that if one of the sets is empty, this condition is met.
For example, if p=[3,1,2]p=[3,1,2] and a=[7,1,4]a=[7,1,4], then the optimal strategy is: separate pp into two parts [3,1][3,1] and [2][2] and then move the 22-element into first set (it costs 44). And if p=[3,5,1,6,2,4]p=[3,5,1,6,2,4], a=[9,1,9,9,1,9]a=[9,1,9,9,1,9], then the optimal strategy is: separate pp into two parts [3,5,1][3,5,1] and [6,2,4][6,2,4], and then move the 22-element into first set (it costs 11), and 55-element into second set (it also costs 11).
Calculate the minimum number of dollars you have to spend.
Input
The first line contains one integer nn (2≤n≤2⋅1052≤n≤2⋅105) — the length of permutation.
The second line contains nn integers p1,p2,…,pnp1,p2,…,pn (1≤pi≤n1≤pi≤n). It's guaranteed that this sequence contains each element from 11 to nn exactly once.
The third line contains nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤1091≤ai≤109).
Output
Print one integer — the minimum number of dollars you have to spend.
Examples
input
Copy
3
3 1 2
7 1 4
output
Copy
4
input
Copy
4
2 4 1 3
5 9 8 3
output
Copy
3
input
Copy
6
3 5 1 6 2 4
9 1 9 9 1 9
output
Copy
2
题意:
给定一个整数n以及一个1~n的全排列,和一个数组a[i]
让你找一个位置划开,将排列分成2个非空的部分,
然后将p[i] 移动到另一个部分的成本是a[i],
问使左边的所有数都比右边的所有的数小需要的最小成本是多少?
思路:
在区间\([1,n-1]\)枚举切割位置i (从p[i] 右边切开,不取n是因为要保证2部分初始非空) ,时间复杂度\(O(n)\)
那么我们知道所有p[i] 位置后面的小于等于 i 的数都要移动到左边,p[i] 位置即前面的大于 i 的数都要移动到右边。
我们尚若可以\(O(logn)\) 时间内得到上面移动操作的cost就可以维护出最小值。
我们想到了线段树。
首先对a[i] 做一个前缀和 数组 sum[i] ,代表将1~i的数都移动到右边需要的cost。
以sum[i] 数组建立区间修改,区间查询最小值的线段树。
然后从1到n-1枚举割切位置i,
对于第i个位置,我们将找到i在p中的位置 id ,将区间\([1,id-1]\) 减去 a[id],区间\([id,n-1]\) 加上a[id]
意义为:在切割位置大于等于i 的时候,不需要将数字i移动到右边部分,又结合线段树维护的是前缀和数组,
那么对于每一个位置i 用线段树的根节点维护的最小值去更新答案ans即可。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
const int maxn = 300010;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
int n;
int p[maxn];
int id[maxn];
ll a[maxn];
ll sum[maxn];
struct node
{
int l, r;
ll laze;
ll val;
} segment_tree[maxn << 2];
void pushup(int rt)
{
segment_tree[rt].val = min(segment_tree[rt << 1].val, segment_tree[rt << 1 | 1].val);
}
void build(int rt, int l, int r)
{
segment_tree[rt].l = l;
segment_tree[rt].r = r;
if (l == r)
{
segment_tree[rt].val = sum[l];
segment_tree[rt].laze = 0ll;
return ;
}
int mid = (l + r) >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
pushup(rt);
}
void pushdown(int rt)
{
segment_tree[rt << 1 | 1].val += segment_tree[rt].laze;
segment_tree[rt << 1 | 1].laze += segment_tree[rt].laze;
segment_tree[rt << 1 ].val += segment_tree[rt].laze;
segment_tree[rt << 1 ].laze += segment_tree[rt].laze;
segment_tree[rt].laze = 0;
}
void update(int rt, int l, int r, int num)
{
if (segment_tree[rt].laze && l != r)
{
pushdown(rt);
}
if (segment_tree[rt].l >= l && segment_tree[rt].r <= r)
{
segment_tree[rt].val += num;
segment_tree[rt].laze += num;
return ;
}
int mid = segment_tree[rt].l + segment_tree[rt].r >> 1;
if (r > mid)
{
update(rt << 1 | 1, l, r, num);
}
if (l <= mid)
{
update(rt << 1, l, r, num);
}
pushup(rt);
}
int main()
{
//freopen("D:\\code\\text\\input.txt","r",stdin);
//freopen("D:\\code\\text\\output.txt","w",stdout);
n = readint();
repd(i, 1, n)
{
p[i] = readint();
id[p[i]] = i;
}
repd(i, 1, n)
{
a[i] = readll();
}
repd(i, 1, n)
{
sum[i] = sum[i - 1] + a[i];
}
ll ans = a[n];
build(1, 1, n - 1);
ans = min(ans, segment_tree[1].val);
int x;
repd(i, 1, n)
{
x = id[i];
if (x != n)
{
update(1, x, n - 1, -a[x]);
}
if (x != 1)
{
update(1, 1, x - 1, a[x]);
}
ans = min(ans, segment_tree[1].val);
}
printf("%lld\n", ans );
return 0;
}
[Educational Codeforces Round 81 (Rated for Div. 2)]E. Permutation Separation(线段树,思维,前缀和)的更多相关文章
- Educational Codeforces Round 51 (Rated for Div. 2) G. Distinctification(线段树合并 + 并查集)
题意 给出一个长度为 \(n\) 序列 , 每个位置有 \(a_i , b_i\) 两个参数 , \(b_i\) 互不相同 ,你可以进行任意次如下的两种操作 : 若存在 \(j \not = i\) ...
- Educational Codeforces Round 47 (Rated for Div. 2)F. Dominant Indices 线段树合并
题意:有一棵树,对于每个点求子树中离他深度最多的深度是多少, 题解:线段树合并快如闪电,每个节点开一个权值线段树,递归时合并即可,然后维护区间最多的是哪个权值,到x的深度就是到根的深度减去x到根的深度 ...
- Educational Codeforces Round 37 (Rated for Div. 2)C. Swap Adjacent Elements (思维,前缀和)
Educational Codeforces Round 37 (Rated for Div. 2)C. Swap Adjacent Elements time limit per test 1 se ...
- Educational Codeforces Round 81 (Rated for Div. 2) A-E简要题解
链接:https://codeforces.com/contest/1295 A. Display The Number 贪心思路,尽可能放置更多位,如果n为奇数,消耗3去放置一个7,剩下的放1 AC ...
- Educational Codeforces Round 81 (Rated for Div. 2) B. Infinite Prefixes
题目链接:http://codeforces.com/contest/1295/problem/B 题目:给定由0,1组成的字符串s,长度为n,定义t = sssssss.....一个无限长的字符串. ...
- 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 == stri ...
- Educational Codeforces Round 81 (Rated for Div. 2)
A 0~9需要多少笔画,自取7和1,判奇偶 #include<bits/stdc++.h> using namespace std; #define ll long long #defin ...
- Educational Codeforces Round 81 (Rated for Div. 2) 题解
过了n天补的题解:D AB就不用说了 C. Obtain The String 思路挺简单的,就是贪心,但是直接贪心的复杂度是O(|s|*|t|),会超时,所以需要用到序列自动机 虽然名字很高端但是就 ...
- Educational Codeforces Round 81 (Rated for Div. 2)E(线段树)
预处理把左集划分为大小为1~i-1时,把全部元素都移动到右集的代价,记作sum[i]. 然后枚举终态时左集的大小,更新把元素i 留在/移动到 左集的代价. 树状数组/线段树处理区间修改/区间查询 #d ...
随机推荐
- 安装Ubuntu后的一些配置
Ubuntu安装的一些配置 搜狗拼音的安装 卸载ibus和它的配置, 卸载顶部面板的键盘指示 sudo apt remove ibus sudo apt purge ibus sudo apt rem ...
- 杭电 2096 小明A+B
小明A+B Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- 【Fine学习笔记】python 文件l操作方法整理
python脚本可以对excel进行创建.读.写.保存成指定文件名,保存到指定路径的操作.整理了以下处理方法: 首先区别几个操作方式: "r" 以读方式打开,只能读文件 , 如 ...
- .NET Runtime at IP 791F7E06 (79140000) with exit code 80131506.
事件類型: 錯誤 事件來源: .NET Runtime 事件類別目錄: 無 事件識別碼: 1023 日期: 2015/12/15 時間: 上午 10:18:52 使用者: N/A 電腦: KM-ERP ...
- jsp分割字符串并遍历
1.先引入JSTL库 <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> ...
- Go文档:go命令
目录 go go bug--启动bug报告 go build--编译包及其依赖包 go clean--删除对象文件和缓存文件 go doc--查看包或符号的文档 go env--打印环境变量 go f ...
- VS2019 发布单文件
在项目.csproj文件下添加 <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework&g ...
- 使用SQL语句还原数据库 2012.3.20
--返回由备份集内包含的数据库和日志文件列表组成的结果集. --主要获得逻辑文件名 USE master RESTORE FILELISTONLY FROM DISK = 'g:\back.Bak' ...
- null值可以赋给引用变量,不能给基本类型
下面正确的写法是? cbyte i=128 boolean i=null long i=0xfffL double i=0.9239d null表示没有地址:null可以赋值给引用变量,不能将null ...
- Jlink不报错的方法
https://blog.csdn.net/yekui6254/article/details/85272767 方法:安装最新的jlink驱动,按下面网址下载 OllyDBG软件,根据上面说的方法修 ...