模拟费用流

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;
}