说在前面的话
今天异常颓废突发奇想,想要把自己之前这道题目的奇怪做法记录一下,可是发现洛谷已经有人捷足先登了。
题解
你发现对于每一个站点,它需要和前面的每一个站点连边,同时对于比他大的和比他小的权值计算方式不一样,我们就考虑用主席树优化建图,然后就好了。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e3+5;
const int INF=1e9+7;
int n,w;
struct Data{int data,pos;}a[N];int L[N],R[N];
bool cmp(const Data a,const Data b){return a.data<b.data;}
int from,to,id[2][N],tot=0;
struct Edge{int nxt,to,flow,cost;};vector<Edge> e;int fir[N<<6];
void add(int u,int v,int x,int y){e.push_back((Edge){fir[u],v,x,y}),fir[u]=e.size()-1;}
struct Per_Seg_Tree{
int rt[2][N];
struct Node{int id,ls,rs;}tr[N<<6];
void insert(int u,int v,int l,int r,int x,int cost){
tr[v]=tr[u];
if(l==r) return add(v,id[1][l],1,cost),add(id[1][l],v,0,-cost);
int mid=(l+r)>>1;
if(x<=mid) tr[v].ls=++tot,insert(tr[u].ls,tr[v].ls,l,mid,x,cost);
else tr[v].rs=++tot,insert(tr[u].rs,tr[v].rs,mid+1,r,x,cost);
add(v,tr[v].ls,INF,0),add(tr[v].ls,v,0,0);
add(v,tr[v].rs,INF,0),add(tr[v].rs,v,0,0);
}
void add_edge(int u,int l,int r,int x,int y,int id,int cost){
if(!u||x>y) return ;
if(x<=l&&r<=y) return add(id,u,1,cost),add(u,id,0,-cost);
int mid=(l+r)>>1;
if(x<=mid) add_edge(tr[u].ls,l,mid,x,y,id,cost);
if(y>mid) add_edge(tr[u].rs,mid+1,r,x,y,id,cost);
}
}t;
queue<int> q;bool vis[N<<6];
int dis[N<<6],cur[N<<6],res=0;
bool bfs(){
for(int i=1;i<=tot;++i) dis[i]=INF,cur[i]=fir[i];
dis[from]=0,vis[from]=true,q.push(from);
while(!q.empty()){
int u=q.front();vis[u]=false,q.pop();
for(int i=fir[u];i>=0;i=e[i].nxt){
int v=e[i].to;
if(!e[i].flow||dis[v]<=dis[u]+e[i].cost) continue;
dis[v]=dis[u]+e[i].cost;
if(!vis[v]) vis[v]=true,q.push(v);
}
}
return dis[to]!=INF;
}
int dfs(int u,int flow){
if(u==to) return flow;
int res=0;vis[u]=true;
for(int i=cur[u];i>=0&&flow;i=e[i].nxt){
int v=e[i].to;cur[u]=i;
if(!e[i].flow||dis[v]!=dis[u]+e[i].cost||vis[v]) continue;
int tmp=dfs(v,min(e[i].flow,flow));
e[i].flow-=tmp,e[i^1].flow+=tmp,flow-=tmp,res+=tmp;
}
return vis[u]=false,res;
}
signed main(){
cin>>n>>w;
for(int i=1;i<=n;++i){
scanf("%lld",&a[i].data),a[i].pos=i;
}
sort(a+1,a+1+n,cmp);
from=++tot,to=++tot;
memset(fir,-1,sizeof(fir));
for(int i=1;i<=n;++i){
id[0][i]=++tot,id[1][i]=++tot;
add(from,id[0][i],1,0),add(id[0][i],from,0,0);
add(id[1][i],to,1,0),add(to,id[1][i],0,0);
}
a[0].data=a[n+1].data=INF;
for(int i=1;i<=n;++i){
t.rt[0][i]=++tot,L[i]=(a[i].data==a[i-1].data)?L[i-1]:i;
t.insert(t.rt[0][i-1],t.rt[0][i],1,n,a[i].pos,-a[i].data);
}
for(int i=n;i>=1;--i){
t.rt[1][i]=++tot,R[i]=(a[i].data==a[i+1].data)?R[i+1]:i;
t.insert(t.rt[1][i+1],t.rt[1][i],1,n,a[i].pos,a[i].data);
}
for(int i=1;i<=n;++i){
add(id[0][i],to,1,w),add(to,id[0][i],0,-w);
// printf("---%lld %lld %lld\n",a[i].pos,L[i],R[i]);
t.add_edge(t.rt[0][R[i]],1,n,1,a[i].pos-1,id[0][a[i].pos],a[i].data);
t.add_edge(t.rt[1][L[i]],1,n,1,a[i].pos-1,id[0][a[i].pos],-a[i].data);
}
while(bfs()) res+=dis[to]*dfs(from,INF);
printf("%lld\n",res);
return 0;
}