模拟费用流
455. 【UER #8】雪灾与外卖
题意:
一条直线上有只老鼠,
个洞。每只老鼠有一个坐标
,每个洞也有一个坐标
。
每个洞有一个容纳量,和一个权值
。
第只老鼠和第
个洞匹配,代价为:
问最小的代价。
题解:
模拟费用流,个人感觉就是个可反悔的堆。
有种情况:
具体见代码
代码:
#include<bits/stdc++.h>
using namespace std;
#define next Next
#define gc getchar
#define int long long
const int inf=1e13;
const int N=1e6+5;
int n,m,ans;
struct node{
int pos,val,sum,opt;
}a[N];
struct Node{
int val,sum;
};
bool operator < (Node a,Node b)
{
return a.val>b.val;
}
priority_queue<Node>Mouse;
priority_queue<Node>Hole;
//char buf[1<<21],*p1=buf,*p2=buf;
//inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline int read()
{
int ret=0,f=0;char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){ret=ret*10+c-48;c=gc();}
if(f)return -ret;return ret;
}
bool cmp(node a,node b)
{
if(a.pos==b.pos)return a.opt>b.opt;
return a.pos<b.pos;
}
signed main()
{
n=read();m=read();
for(int i=1;i<=n;i++)a[i].pos=read();
int gs=n,sum=0;
for(int i=1;i<=m;i++)
{
a[++gs].pos=read();
a[gs].val=read();
a[gs].sum=read();
a[gs].opt=1;
sum+=a[gs].sum;
}
if(sum<n){puts("-1");return 0;}
gs++;
a[gs].pos=-inf;
a[gs].val=0;
a[gs].sum=n;
a[gs].opt=1;
gs++;
a[gs].pos=inf;
a[gs].val=0;
a[gs].sum=n;
a[gs].opt=1;
sort(a+1,a+gs+1,cmp);
for(int i=1;i<=gs;i++)
{
if(a[i].opt==1)
{
int t=a[i].sum;
while(!Mouse.empty()&&t&&a[i].pos+a[i].val+Mouse.top().val<0)
{
Node u=Mouse.top();Mouse.pop();
int d=min(t,u.sum);
ans+=d*(a[i].pos+a[i].val+u.val);
Hole.push((Node){-2*a[i].pos-u.val,d});
//4.洞找了鼠,变成洞,可以使后面的鼠来换鼠(不换就是2)
t-=d;
u.sum-=d;
if(u.sum)Mouse.push(u);
}
if(a[i].sum!=t)
{
Mouse.push((Node){-a[i].pos-a[i].val,a[i].sum-t});
//5.洞找了鼠,变成鼠,可以使后面的洞来换洞
//洞没有权值的情况下,匹配肯定没有交叉的情况
//洞有权值,就会出现不要某个洞,而去选择后面的洞
}
if(t)Hole.push((Node){-a[i].pos+a[i].val,t});
}
else{
Node u=Hole.top();Hole.pop();
ans+=a[i].pos+u.val;
Mouse.push((Node){-2*a[i].pos-u.val,1});
//3.鼠找了洞,变成鼠,可以使后面的洞来换洞 (不换就是1)
//为什么没有6.鼠找了洞,变成洞,可以可以使后面的鼠来换鼠
//因为鼠是没有权值的,所以不会出现交叉的情况
//即不会出现洞1-鼠2,洞2-鼠1,一定是洞1-鼠1,洞2-鼠2
u.sum--;
if(u.sum)Hole.push(u);
}
}
cout<<ans;
return 0;
}
/*
5 5
10 3 1 9 1
4 0 1
2 2 1
5 0 2
5 1 1
4 4 1
18
*/ 注意:
由于老鼠没有权值,所以不需要。
同理,如果洞也没有权值,那么就不需要了。
Masha与老鼠
题意:
一条直线上有只老鼠,
个洞。每只老鼠有一个坐标
,每个洞也有一个坐标
。
每个洞有一个容纳量。
第只老鼠和第
个洞匹配,代价为:
问最小的代价。
题解
就是上一题,洞没有权值的情况。
由于洞没有权值,那么就不需要了。
代码:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
#define next Nxt
#define last Lst
//#define gc getchar
#define int long long
const int N=3e6+5;
int n,m,ans;
struct node{
int pos,sum,opt;
}a[N];
struct Node{
int val,sum;
};
bool operator < (Node a,Node b)
{
return a.val>b.val;
}
priority_queue<int,vector<int>,greater<int> >Mouse;
priority_queue<Node>Hole;
char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline int read()
{
int ret=0,f=0;char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){ret=ret*10+c-48;c=gc();}
if(f)return -ret;return ret;
}
bool cmp(node a,node b)
{
return a.pos<b.pos;
}
signed main()
{
n=read();m=read();
for(int i=1;i<=n;i++)a[i].pos=read();
int gs=n,sum=0;
for(int i=1;i<=m;i++)
{
gs++;
a[gs].pos=read();a[gs].sum=read();a[gs].opt=1;
sum+=a[gs].sum;
}
if(sum<n){puts("-1");return 0;}
a[++gs]=(node){-200000000000,n,1};
a[++gs]=(node){200000000000,n,1};
sort(a+1,a+gs+1,cmp);
for(int i=1;i<=gs;i++)
{
if(a[i].opt==1)
{
int t=a[i].sum;
while(!Mouse.empty()&&t&&a[i].pos+Mouse.top()<0)
{
ans+=a[i].pos+Mouse.top();
Hole.push((Node){-2*a[i].pos-Mouse.top(),1});
Mouse.pop();
t--;
}
if(t)Hole.push((Node){-a[i].pos,t});
}
else{
Node u=Hole.top();Hole.pop();
ans+=a[i].pos+u.val;
Mouse.push(-2*a[i].pos-u.val);
u.sum--;
if(u.sum)Hole.push(u);
}
}
cout<<ans;
} 
京公网安备 11010502036488号