loj#6518-「雅礼集训 2018 Day11」序列【整体二分,dp,线段树】

news/2025/1/8 15:23:22/

正题

题目链接:https://loj.ac/p/6518


题目大意

一个长度为 n n n的序列 a a a,你可以花费 1 1 1的代价让一个数 + 1 +1 +1或者 − 1 -1 1,给出 m m m个限制形如第 k k k个数要是区间 [ l , r ] [l,r] [l,r]的最大/最小值。

求满足所有限制的最小代价

1 ≤ n ≤ 5000 , 1 ≤ a i ≤ 1 0 5 1\leq n\leq 5000,1\leq a_i\leq 10^5 1n5000,1ai105


解题思路

一个保序回归问题,我们考虑整体二分。

二分到 m i d mid mid时,我们就只考虑每个数选为 m i d mid mid还是 m i d + 1 mid+1 mid+1,选为 m i d mid mid的最终 ≤ m i d \leq mid mid,选为 m i d + 1 mid+1 mid+1的最终 > m i d > mid >mid

然后是怎么处理一个 m i d mid mid,考虑使用 d p dp dp,用 0 0 0表示 m i d mid mid 1 1 1表示 m i d + 1 mid+1 mid+1,那么序列就会被分成很多 01 01 01交错的段,设 f i , 0 / 1 f_{i,0/1} fi,0/1表示上一段的结尾是 i i i,且是 0 / 1 0/1 0/1段。

然后考虑怎么转移,我们将一个条件 [ t y p e , l , r , k ] [type,l,r,k] [type,l,r,k]分为 [ t y p e , l , k , k ] [type,l,k,k] [type,l,k,k] [ t y p e , k , r , k ] [type,k,r,k] [type,k,r,k],然后用线段树维护权值。

对于形如 [ t y p e , l , k , k ] [type,l,k,k] [type,l,k,k]的条件,这里设 t y p e = 1 type=1 type=1,那在我们取 0 0 0段时如果包括了 k k k那么必须包括整个 [ l , k ] [l,k] [l,k],也就是左端点的选择不能为 ( l , k ] (l,k] (l,k],我们可以视为在线段树上去掉一段可选区间。

对于形如 [ t y p e , k , r , k ] [type,k,r,k] [type,k,r,k]的条件,同样设 t y p e = 1 type=1 type=1,那我们在取 0 0 0段时如果包括了 k k k那么必须包括整个 [ k , r ] [k,r] [k,r],也就是如果 i ∈ [ k , r ] i\in[k,r] i[k,r],那么我们上一个转移点 j j j的选择必须有 j > k j>k j>k,可以用单调栈来维护这些限制。

需要注意的点就是线段树的清空需要只清空修改过的点,否则会错。

时间复杂度: O ( a log ⁡ a log ⁡ n ) O(a\log a\log n) O(alogalogn)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#define ll long long
using namespace std;
const ll N=5100,M=N<<2,inf=1e9;
ll n,m,a[N],ans,lim[2][N],rim[2][N];
ll p[N],p0[N],p1[N],f[2][N],g[2][N];
stack<ll> d0,d1;
struct SegTree{ll cl[M],p[M],w[M],lazy[M];ll ans,ansp,clt;bool v[M];void Add(ll x){if(!v[x])v[x]=1,cl[++clt]=x;return;}void Downdata(ll x){Add(x);if(!lazy[x])return;Add(x*2);Add(x*2+1);lazy[x*2]+=lazy[x];w[x*2]+=lazy[x];lazy[x*2+1]+=lazy[x];w[x*2+1]+=lazy[x];lazy[x]=0;return;}void Merge(ll x){if(w[x*2]<w[x*2+1])w[x]=w[x*2],p[x]=p[x*2];else w[x]=w[x*2+1],p[x]=p[x*2+1];return;}void Change(ll x,ll L,ll R,ll l,ll r,ll val){if(L==l&&R==r){Add(x);lazy[x]+=val;w[x]+=val;return;}ll mid=(L+R)>>1;Downdata(x);if(r<=mid)Change(x*2,L,mid,l,r,val);else if(l>mid)Change(x*2+1,mid+1,R,l,r,val);else Change(x*2,L,mid,l,mid,val),Change(x*2+1,mid+1,R,mid+1,r,val);Merge(x);return;}void Ins(ll x,ll L,ll R,ll pos,ll val,ll pr){if(L==R){Add(x);if(w[x]>val)w[x]=val,p[x]=pr;return;}ll mid=(L+R)>>1;Downdata(x);if(pos<=mid)Ins(x*2,L,mid,pos,val,pr);else Ins(x*2+1,mid+1,R,pos,val,pr);Merge(x);return;}void Query(ll x,ll L,ll R,ll l,ll r){if(L==l&&R==r){if(w[x]<ans)ans=w[x],ansp=p[x];return;}ll mid=(L+R)>>1;Downdata(x);if(r<=mid)Query(x*2,L,mid,l,r);else if(l>mid)Query(x*2+1,mid+1,R,l,r);else Query(x*2,L,mid,l,mid),Query(x*2+1,mid+1,R,mid+1,r);}void Ask(ll l,ll r){ans=inf;Query(1,1,n,l,r);return;}void Clear(){for(ll i=1;i<=clt;i++){w[cl[i]]=inf;v[cl[i]]=lazy[cl[i]]=0;}clt=0;return;}
}T0,T1;
void solve(ll l,ll r,ll L,ll R){if(l>r)return;if(L==R){for(ll i=l;i<=r;i++)ans+=abs(a[p[i]]-L);return;}T0.Clear();T1.Clear();while(!d0.empty())d0.pop();d0.push(0);while(!d1.empty())d1.pop();d1.push(0);T0.Ins(1,1,n,1,0,0);T1.Ins(1,1,n,1,0,0);ll mid=(L+R)>>1;for(ll i=l;i<=r;i++){f[0][i]=f[1][i]=inf;if(i>l&&lim[0][p[i]]<p[i])T0.Change(1,1,n,lim[0][p[i]]+1,p[i],inf);if(i>l&&lim[1][p[i]]<p[i])T1.Change(1,1,n,lim[1][p[i]]+1,p[i],inf);T1.Change(1,1,n,1,p[i],abs(mid-a[p[i]]));T0.Change(1,1,n,1,p[i],abs(mid+1-a[p[i]]));while(!d0.empty()&&rim[0][d0.top()]<=rim[0][p[i]])d0.pop();while(!d1.empty()&&rim[1][d1.top()]<=rim[1][p[i]])d1.pop();if(i<r){while(!d0.empty()&&rim[0][d0.top()]<p[i+1])d0.pop();while(!d1.empty()&&rim[1][d1.top()]<p[i+1])d1.pop();if(rim[0][p[i]]>=p[i+1])d0.push(p[i]);if(rim[1][p[i]]>=p[i+1])d1.push(p[i]);}else{while(d0.size()>1)d0.pop();while(d1.size()>1)d1.pop();}if(d1.top()<p[i]){T1.Ask(d1.top()+1,p[i]);f[0][i]=T1.ans;g[0][i]=T1.ansp;}if(d0.top()<p[i]){T0.Ask(d0.top()+1,p[i]);f[1][i]=T0.ans;g[1][i]=T0.ansp;}if(i<r){T0.Ins(1,1,n,p[i]+1,f[0][i],i);T1.Ins(1,1,n,p[i]+1,f[1][i],i);}}ll t0=0,t1=0,i=r,k=(f[0][r]<f[1][r])?0:1;while(i){for(ll j=i;j>max(g[k][i],l-1);j--)if(k)p1[++t1]=p[j];else p0[++t0]=p[j];i=g[k][i];k^=1;}for(ll i=1;i<=t0;i++)p[l+i-1]=p0[t0-i+1];for(ll i=1;i<=t1;i++)p[l+t0+i-1]=p1[t1-i+1];solve(l,l+t0-1,L,mid);solve(l+t0,r,mid+1,R);return;
}
signed main()
{freopen("hack.in","r",stdin);scanf("%lld%lld",&n,&m);rim[0][0]=rim[1][0]=inf;for(ll i=1;i<=n;i++)scanf("%lld",&a[i]);memset(lim,0x3f,sizeof(lim));for(ll i=1,t,l,r,k;i<=m;i++){scanf("%lld%lld%lld%lld",&t,&l,&r,&k);lim[t][k]=min(lim[t][k],l);rim[t][k]=max(rim[t][k],r);}for(ll i=1;i<=n;i++)p[i]=i;memset(T0.w,0x3f,sizeof(T0.w));memset(T1.w,0x3f,sizeof(T1.w));solve(1,n,1,1e5);printf("%lld\n",ans);return 0;
}

http://www.ppmy.cn/news/297025.html

相关文章

hdu6518

http://acm.hdu.edu.cn/showproblem.php?pid6518 看代码&#xff0c;很简单 #include <iostream> #include <algorithm> #include <cstdio> #include <cstring> #include <math.h> #include <map> #include <set> #include <qu…

【vue2】axios请求与axios拦截器的使用详解

&#x1f973;博 主&#xff1a;初映CY的前说(前端领域) &#x1f31e;个人信条&#xff1a;想要变成得到&#xff0c;中间还有做到&#xff01; &#x1f918;本文核心&#xff1a;当我们在路由跳转前与后我们可实现触发的操作 【前言】ajax是一种在javaScript代码中发请…

1.平台介绍:FISCO BCOS 区块链

引言&#xff1a; 区块链技术作为一种分布式、安全可信的数据记录和交互方式&#xff0c;正逐渐在各行各业展现出巨大潜力。然而&#xff0c;公共区块链的隐私性和性能限制使得企业更倾向于采用联盟链或私有链解决方案。 FISCO BCOS&#xff08;Blockchain Open Consortium O…

回调函数(callback)

1.什么是回调函数&#xff08;callback&#xff09;呢&#xff1f; 把函数当作参数传到另外一个函数中&#xff0c;当需要用这个函数时&#xff0c;再回调运行&#xff08;&#xff09;这个函数。 回调函数是一段可执行的代码段&#xff0c;它作为一个参数传递给其他的代码&a…

安装docker环境,并制作docker镜像

docker环境安装 进入linux虚机后&#xff0c;安装docker环境&#xff0c;制作docker镜像并运行&#xff0c;进入运行中的容器&#xff0c;查看挂载的日志或报告 1.安装docker sudo curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun 2.使用docker仓库安装…

TCL微型计算机如何投屏,tcl电视怎么投屏

电视机投屏有两种不同的方法&#xff0c;大家可以根据自己的实际情况选择投屏&#xff0c;一般常见的是无线电视机投屏设置方法&#xff0c;大家可以了解了解。 一、无线连接投屏方法 使用无线连接方式首先要保证电视是智能电视&#xff0c;另外手机和电视需要保持在同一个WiFi…

解决TCL电视机上电默认是网络主页的问题

家里的老TCL电视用了十来年了&#xff0c;屏幕太小&#xff0c;爷爷有点看不见&#xff0c;所以买了TCL 55L680。 老人家不会用智能电视&#xff0c;他们平时是用机顶盒的&#xff0c;操作简单&#xff0c;但是TCL每次上电都是网络主页&#xff0c;就很气人&#xff0c;设置里…

初识Tcl(八):Tcl 列表

列表是Tcl的基本可用数据类型之一。它是用于表示项目的有序集合。它可以包括不同类型的在同一列表的项目。此外&#xff0c;一个列表可以包含另一个列表。 需要注意的一个重要的事情是&#xff0c;列表表示为完全串并处理在需要时&#xff0c;形成的各个项目。所以要避免大的列…