P5331 [SNOI2019]通信
链接:https://www.luogu.com.cn/problem/P5331
题解:发现不好设状态,考虑网络流:
,流量,费用。
,流量,费用。
,流量,费用。
(),流量,费用。
然后加上。
直接做不行,考虑优化:
这个堆模拟费用流要,过不了。
它介绍了一个优化费用流的做法,但也卡不过。
这时考虑数据结构优化连边,将序列分治以下,排序后可以前缀优化连边,这样就可以通过了。
#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
struct node
{
long long v,data,cost,nxt;
};
node edge[2000001];
int head[120003],len;
bool used[120003];
long long n,W,mincostmaxflow,a[1001],dis[120003],incf[120003],pv[120003],N,s,t;
int read()
{
char c=0;
int sum=0;
while (c<'0'||c>'9')
c=getchar();
while ('0'<=c&&c<='9')
{
sum=sum*10+c-'0';
c=getchar();
}
return sum;
}
void add(int x,int y,int z,int w)
{
edge[++len].v=y,edge[len].data=z,edge[len].cost=w,edge[len].nxt=head[x],head[x]=len;
edge[++len].v=x,edge[len].data=0,edge[len].cost=-w,edge[len].nxt=head[y],head[y]=len;
return;
}
queue<int>q;
bool spfa()
{
int top;
for (int i=s;i<=t;++i)
dis[i]=1e18;
dis[s]=0;
q.push(s);
incf[s]=1e18;
while (!q.empty())
{
top=q.front();
q.pop();
used[top]=0;
for (int i=head[top];i>0;i=edge[i].nxt)
if (edge[i].data&&dis[edge[i].v]>dis[top]+edge[i].cost)
{
incf[edge[i].v]=min(incf[top],edge[i].data);
dis[edge[i].v]=dis[top]+edge[i].cost;
pv[edge[i].v]=i;
if (!used[edge[i].v])
{
used[edge[i].v]=1;
q.push(edge[i].v);
}
}
}
if (dis[t]!=1e18)
return 1;
return 0;
}
long long EK()
{
int x=t;
while (x!=s)
{
edge[pv[x]].data-=incf[t];
edge[pv[x]^1].data+=incf[t];
x=edge[pv[x]^1].v;
}
return dis[t]*incf[t];
}
struct ps
{
int num,data;
bool operator < (const ps &a)const
{
return data<a.data;
}
};
ps tong[100001];
void cdq(int l,int r)
{
if (l==r)
return;
int mid=(l+r)/2;
cdq(l,mid);
sort(tong+l,tong+mid+1);
cdq(mid+1,r);
sort(tong+mid+1,tong+r+1);
int pos=l-1;
for (int i=mid+1;i<=r;++i)
{
while (pos<mid&&tong[pos+1].data<=tong[i].data)
{
++pos;
if (pos==l)
add(tong[l].num,++N,1,0);
else
{
add(tong[pos].num,++N,1,0);
add(N-1,N,1e9,tong[pos].data-tong[pos-1].data);
}
}
if (pos>=l)
add(N,tong[i].num+n,1,tong[i].data-tong[pos].data-W);
}
pos=mid+1;
for (int i=r;i>=mid+1;--i)
{
while (pos>l&&tong[pos-1].data>tong[i].data)
{
--pos;
if (pos==mid)
add(tong[mid].num,++N,1,0);
else
{
add(tong[pos].num,++N,1,0);
add(N-1,N,1e9,tong[pos+1].data-tong[pos].data);
}
}
if (pos<=mid)
add(N,tong[i].num+n,1,tong[pos].data-tong[i].data-W);
}
return;
}
int main()
{
len=1;
n=read(),W=read();
for (int i=1;i<=n;++i)
{
a[i]=read();
tong[i].num=i,tong[i].data=a[i];
}
N=2*n;
s=0;
for (int i=1;i<=n;++i)
add(s,i,1,0);
cdq(1,n);
t=N+1;
for (int i=1;i<=n;++i)
{
add(i+n,t,1,0);
add(i,t,1,0);
}
while (spfa())
mincostmaxflow+=EK();
printf("%lld\n",mincostmaxflow+n*W);
return 0;
}
作者:zhouhuanyi
出处:https://www.cnblogs.com/zhouhuanyi/p/16983735.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现