[APIO 2015] 八邻旁之桥

题目描述:

QAQ…

题目分析:

看上去看不可做…
K只有可能为 1 和 2
我们想一下1的情况怎么做
如果工作地点在一侧,那么路程就是 r-l
然后我们对于不在一侧的线段端点求个中位数 肯定能使总路程最小…
当K为2的时候
取每个线段的中点,如果靠近左边的桥,就往左边过桥,否则往右边过桥。
枚举一个分割点,然后两边都是k=1的情况,用线段树求 | |

题目链接:

COGS 1984
Luogu 3644

Ac 代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define int long long
using namespace std;
const int maxm=1600001;
int n,t,k;
int s[maxm<<2],c[maxm<<2];
int hash[maxm],ans[maxm];;
struct node{
    int l,r;
}link[maxm];
inline bool comp(node x,node y){return x.l+x.r<y.l+y.r;}
void insert(int o,int l,int r,int ind,int v)
{
    if(l>=r)
    {
        c[o]++,s[o]+=v;
        return;
    }
    int mid=(l+r)>>1;
    ind<=mid?insert((o<<1),l,mid,ind,v):insert((o<<1)|1,mid+1,r,ind,v);
    s[o]=s[(o<<1)]+s[(o<<1)|1],c[o]=c[(o<<1)]+c[(o<<1)|1];
}
int ask(int o,int l,int r,int x)
{
    if(l>=r) return hash[l]*x;
    int mid=(l+r)>>1;
    return c[(o<<1)]<x?s[(o<<1)]+ask((o<<1)|1,mid+1,r,x-c[(o<<1)]):ask((o<<1),l,mid,x);
}
inline int query(int x){return s[1]-2*ask(1,1,t,x);} 
signed main()
{
    //freopen("cstdiorank1AK.in","r",stdin); 
    //freopen("cstdiorank1AK.out","w",stdout); 
    int Ans=0,tot=0,num=0;
    scanf("%lld%lld",&k,&n);
    for(int i=1;i<=n;i++)
    {
        char s1[10],s2[10];
        int l,r;
        scanf("%s%lld%s%lld",s1,&l,s2,&r);
        if(l>r) std::swap(l,r);
        if(s1[0]==s2[0]) Ans+=r-l;
        else 
        {
            Ans++;
            link[++tot].l=l,link[tot].r=r;
            hash[++num]=l,hash[++num]=r;
        } 
    }
    n=tot;
    sort(hash+1,hash+num+1);
    sort(link+1,link+n+1,comp);
    t=unique(hash+1,hash+num+1)-hash-1;
    for(int i=1;i<=n;i++)
    {
        link[i].l=lower_bound(hash+1,hash+t+1,link[i].l)-hash;
        link[i].r=lower_bound(hash+1,hash+t+1,link[i].r)-hash;
    }
    for(int i=1;i<=n;i++)
    {
        insert(1,1,t,link[i].l,hash[link[i].l]);
        insert(1,1,t,link[i].r,hash[link[i].r]);
        ans[i]=query(i);
    }
    if(k==1) printf("%lld\n",ans[n]+Ans);
    else
    {
        memset(s,0,sizeof(s));
        memset(c,0,sizeof(c));
        int minx=ans[n];
        for(int i=n;i>=1;i--)
        {
            insert(1,1,t,link[i].l,hash[link[i].l]);
            insert(1,1,t,link[i].r,hash[link[i].r]);
            minx=std::min(minx,ans[i-1]+query(n-i+1));
        }
        printf("%lld\n",minx+Ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_35914587/article/details/80242954