[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 ...
随机推荐
- Python基础模块整理
1.shutil :可以用来对文件进行基本操作(拷贝,剪切等) 2.glob :提供了一个函数用于从目录通配符搜索中生成文件列表 3.datetime :日期和时间的处理 4.zlib ...
- 吴裕雄--天生自然Numpy库学习笔记:NumPy 排序、条件刷选函数
numpy.sort() 函数返回输入数组的排序副本.函数格式如下: numpy.sort(a, axis, kind, order) 参数说明: a: 要排序的数组 axis: 沿着它排序数组的轴, ...
- 炼金术(2): 为什么要用issue管理软件
在项目开发中,存在的无数的任务分解,问题管理,流程跟踪.因为直接说话或者直接在IM里喊话是很容易的,所以在一个还没有习惯使用issue管理软件的团队中,直接说话或者直接在IM里AT,就在某些时候变成了 ...
- html5或者移动端暴力定位城市-高德地图,可以取到当前的城市code,亲测好用
复制 粘贴到html中打开!!!!! <!doctype html> <html> <head> <meta charset="utf-8" ...
- 【Javaweb】Servlet的xml和注解配置
1.xml <%@ page language="java" contentType="text/html;" %> <!DOCTYPE ht ...
- WCF 数据传输SIZE过大
1.当客户端调用WCF服务时,接受数据过大,可通过以下配置解决 <basicHttpBinding> <binding name="BasicHttpBinding_Wcf ...
- 一个不会coding的girl Linux日常之命令awk
Linux日常之命令awk 参考:http://www.zsythink.net/archives/tag/awk/ 一. 命令awk简介 1. awk是一种编程语言,用于对文本和数据进行处理的 2. ...
- python脚本调用iftop 统计业务应用流量
因公司服务器上部署应用较多,在有大并发访问.业务逻辑有问题的情况下反复互相调用或者有异常流量访问的时候,需要对业务应用进行故障定位,所以利用python调用iftop命令来获取应用进程流量,结合zab ...
- JS实现对对象的深拷贝
手动遍历对象拷贝 /** * 深拷贝 * @param {*} obj 拷贝对象(object or array) * @param {*} cache 缓存数组 */ function deepCo ...
- Tomcat认识
Tomcat目录结构: bin:存放启动和关闭的一些脚本 common:共享(部署在该服务器上的一些)jar包 conf:存放服务器的一些配置文件 webapps:部署文件 work:服务器运行时,产 ...