首先这题的p是一个排列,说明1~n每个整数出现且仅出现一次,并且很容易知道每个数的位置。之前做过一些线段树离散化的题目,都是离散成下标然后建树维护。
首先,如果分完之后有一个集合为空,则很容易ans=min(val[1],val[n]),然后将val的前缀和建树,维护n-1个间隔
对于一个数i,将sum[1]~sum[pos[i]-1]加上val[pos[i]]
将sum[pos[i]]~sum[n-1]减去val[pos[i]]
然后每次查询sum的最小值
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#define ll long long
using namespace std;
int n,q;
struct node
{
ll sum;
ll lazy;
}tree[200000*4+100];
ll a[200010];
int x,y;
ll z;
int wei[200010];
ll val[200010];
ll sum[200010];
void pushup(int pos)
{
tree[pos].sum=min(tree[pos*2].sum,tree[pos*2+1].sum);
}
void build(int pos,int l,int r)
{
tree[pos].lazy=0;
if (l==r)
{
tree[pos].sum=sum[l];
return ;
}
int mid=(l+r)/2;
build(pos*2,l,mid);
build(pos*2+1,mid+1,r);
pushup(pos);
}
void pushdown(int pos,int l,int r)
{
if (tree[pos].lazy!=0)
{
tree[pos<<1].lazy+=tree[pos].lazy;
tree[pos<<1|1].lazy+=tree[pos].lazy;
int mid=(l+r)/2;
tree[pos<<1].sum+=tree[pos].lazy;
tree[pos<<1|1].sum+=tree[pos].lazy;
tree[pos].lazy=0;
}
}
ll query(int pos,int l,int r,int x,int y)
{
ll ans=100000000000000000;
int mid=(l+r)/2;
if (x<=l&&y>=r)
{
return tree[pos].sum;
}
pushdown(pos,l,r);
if (x<=mid)
{
ans=min(ans,query(pos*2,l,mid,x,y));
}
if (y>mid)
{
ans=min(ans,query(pos*2+1,mid+1,r,x,y));
}
return ans;
}
void update(int pos,int l,int r,int x,int y,ll z)
{
if (x<=l&&y>=r)
{
tree[pos].lazy+=z;
tree[pos].sum+=z;
return;
}
pushdown(pos,l,r);
int mid=(l+r)/2;
if (x<=mid)
{
update(pos*2,l,mid,x,y,z);
}
if (y>mid)
{
update(pos*2+1,mid+1,r,x,y,z);
}
pushup(pos);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
wei[a[i]]=i;
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&val[i]);
sum[i]=sum[i-1]+val[i];
}
build(1,1,n-1);
ll ans=min(val[1],val[n]);
for(int i=1;i<=n;i++)
{
int pos=wei[i];
if (pos!=1)
{
update(1,1,n-1,1,pos-1,val[pos]);
}
if (pos!=n)
{
update(1,1,n-1,pos,n-1,-val[pos]);
}
ans=min(ans,query(1,1,n-1,1,n-1));
}
printf("%lld\n",ans);
}