1. 程式人生 > >「Luogu3357」 最長k可重線段集問題

「Luogu3357」 最長k可重線段集問題

lower span str getc ios iostream .html problem esp

「Luogu3357」 最長k可重線段集問題

problem

Solution

與「Luogu3357」 最長k可重區間集問題類似,但此題需要考慮斜率不存在的線段

我們將每個線段的兩個端點中\(x\)坐標較小的那一個認為是線段的起點,另一個為終點

考慮拆點,我們將坐標上的每一個點拆成兩個點\(2*x,2*x+1\)。對於一條線段,如果\(x\)是它的起點,將它設為\(2*x+1\),否則設為\(2*x\),這樣我們就把每個坐標拆成了兩個類似“出點”和“入點”的東西

剩下的連邊方式和區間沒有區別

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <queue>
#define maxn 25005
using namespace std;
typedef long long ll;

template <typename T>void read(T &t)
{
    t=0;char c=getchar();ll f=0;
    while(!isdigit(c)){f|=c=='-';c=getchar();}
    while(isdigit(c)){t=t*10+c-'0';c=getchar();}
    if(f)t=-t;
}

const ll inf=0x3f3f3f3f3f3f3f3f;
ll n,K;
ll xa[maxn],xb[maxn],z[maxn];
ll s,t;
ll ansc;

struct edge
{
    ll u,v,f,c,nxt;
}g[maxn];

ll head[maxn],ecnt=1;
void eADD(ll u,ll v,ll f,ll c)
{
    g[++ecnt].u=u;
    g[ecnt].v=v;
    g[ecnt].f=f;
    g[ecnt].c=c;
    g[ecnt].nxt=head[u];
    head[u]=ecnt;
}

inline ll getz(ll xa,ll xb,ll ya,ll yb)
{
    return sqrt((xa-xb)*(xa-xb)+(ya-yb)*(ya-yb));
}

ll dist[maxn],inq[maxn],minf[maxn];
ll pree[maxn],prev[maxn];
bool SPFA()
{
    memset(dist,0x3f,sizeof(dist));
    memset(minf,0x3f,sizeof(minf));
    queue<int> q;
    dist[s]=0;
    inq[s]=1;
    q.push(s);
    while(!q.empty())
    {
        ll u=q.front();
        q.pop();
        inq[u]=0;
        for(register ll i=head[u];i;i=g[i].nxt)
        {
            ll v=g[i].v;
            if(g[i].f && dist[v]>dist[u]+g[i].c)
            {
                prev[v]=u,pree[v]=i;
                dist[v]=dist[u]+g[i].c;
                minf[v]=min(minf[u],g[i].f);
                if(!inq[v])
                {
                    inq[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return dist[t]<inf;
}

int main()
{
    read(n),read(K);
    ll ocr[maxn<<1];
    for(register ll i=1;i<=n;++i)
    {
        ll ya,yb;
        read(xa[i]),read(ya),read(xb[i]),read(yb),z[i]=getz(xa[i],xb[i],ya,yb);
        xa[i]<<=1,xb[i]<<=1;
        if(xa[i]>xb[i])swap(xa[i],xb[i]);
        if(xa[i]==xb[i])xb[i]|=1;
        else xa[i]|=1;
        ocr[++ocr[0]]=xa[i],ocr[++ocr[0]]=xb[i];
    }
    sort(ocr+1,ocr+ocr[0]+1);
    ocr[0]=unique(ocr+1,ocr+ocr[0]+1)-ocr-1;
    for(register ll i=1;i<=n;++i)
        xa[i]=lower_bound(ocr+1,ocr+ocr[0]+1,xa[i])-ocr,xb[i]=lower_bound(ocr+1,ocr+ocr[0]+1,xb[i])-ocr;
    s=0,t=ocr[0]+1;
    eADD(s,1,K,0),eADD(1,s,0,0);
    eADD(ocr[0],t,K,0),eADD(t,ocr[0],0,0);
    for(register ll i=1;i<ocr[0];++i)
        eADD(i,i+1,inf,0),eADD(i+1,i,0,0);
    for(register ll i=1;i<=n;++i)
        eADD(xa[i],xb[i],1,-z[i]),eADD(xb[i],xa[i],0,z[i]);
    while(SPFA())
    {
        ansc+=dist[t]*minf[t];
        for(register ll i=t;i!=s;i=prev[i])
        {
            g[pree[i]].f-=minf[t];
            g[pree[i]^1].f+=minf[t];
        }
    }
    printf("%lld",-ansc);
    return 0;
}

「Luogu3357」 最長k可重線段集問題