zoukankan      html  css  js  c++  java
  • APIO2015 八邻旁之桥

    传送门

    这道题看起来十分的不可做……可能是我数学太差智商太低了orz。

    首先如果一个人的家和办公室在同一侧那就完全不用考虑,把结果记下来就行。

    然后我们先考虑k=1的情况。因为只能建1座桥,那么我们发现(除去过桥一个单位长度不算)答案就是sigma(abs(ai-x)  + abs(bi-x)),其中ai,bi表示区间的开始和末尾,这样我们发现区间的开始和末尾并没有本质上的区别……所以我们直接把所有端点都排个序然后直接找到中位数(r),答案就是sigma(r-ai) (i<=r) + sigma(ai - r) (i >= r) 然后实际中计算的时候非常的简洁,只要把所有小于中位数的答案加起来,把所有大于中位数的答案也加起来,两者差值+预处理结果就是答案。

    那么k=2的时候怎么办呢?这个我又没想到……首先我们可以这么想,找到每个区间的中点,如果中点更靠近左边的桥那么就从左边过桥,否则从右边过桥(这个还是比较显然的)。于是我们先把所有区间按照l+r从小到大排序(中点坐标),再选择枚举一个分割线(分割线左边的全部从左边过桥,右边的从右边过桥),这样我们就把两边分成了两个k=1的情况。

    之后的问题就是怎么快速计算。我们使用线段树维护中位数(r),维护区间内元素个数(k)和距离总和(s),这样的话一个区间的答案就是k*loc[r] - s + s1 - k1*loc[r],(前面是中位数左边的,后面是中位数右边的),loc记录这个点所对应的位置。然后分割线另一端的也一样,开两个线段树维护即可。

    一开始首先把右边的树填满,之后分割线每移动一次,把对应的从右树中删除,加到左树里。

    然后这题有俩坑,第一个是有可能区间的末尾比起点小,这时候要先swap一遍,第二个就是有可能不需要过河…………这样的时候直接特判输出就行…………

    看一下代码。

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    #include<utility>
    #include<map>
    #define pr pair<int,int>
    #define mp make_pair
    #define fi first
    #define sc second
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    using namespace std;
    typedef long long ll;
    const int M = 100005;
    const int N = 10000005;
    const ll INF = 1000000000000000009;
     
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >='0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    int loc[M<<2],n,k,s,ter,tot,cnt,len;
    //tot records the number of loc,cnt records the number of segments(node)
    char s1[5],s2[5];
    ll ans,minn = INF;
    struct node
    {
        int l,r;
        bool operator < (const node &g)const
        {
            return l + r < g.l + g.r;
        }
    }d[M<<2];
    struct seg
    {
        ll v[M<<3],sz[M<<3];
        void modify(int p,int l,int r,int pos,int x)
        {
        if(l == r)
        {
            v[p] += x * loc[pos];
            sz[p] += x;
            return;
        }
        int mid = (l+r) >> 1;
        if(pos <= mid) modify(p<<1,l,mid,pos,x);
        else modify(p<<1|1,mid+1,r,pos,x);
        v[p] = v[p<<1] + v[p<<1|1];
        sz[p] = sz[p<<1] + sz[p<<1|1];
        }
        int find(int p,int l,int r,int x)
        {
        if(l == r) return l;
        int mid = (l+r) >> 1;
        if(x <= sz[p<<1]) return find(p<<1,l,mid,x);
        else return find(p<<1|1,mid+1,r,x - sz[p<<1]);
        }
        ll size(int p,int l,int r,int kl,int kr)
        {
        if(l == kl && r == kr) return sz[p];
        int mid = (l+r) >> 1;
        if(kr <= mid) return size(p<<1,l,mid,kl,kr);
        else if(kl > mid) return size(p<<1|1,mid+1,r,kl,kr);
        else return size(p<<1,l,mid,kl,mid) + size(p<<1|1,mid+1,r,mid+1,kr);
        }
        ll sum(int p,int l,int r,int kl,int kr)
        {
        if(l == kl && r == kr) return v[p];
        int mid = (l+r) >> 1;
        if(kr <= mid) return sum(p<<1,l,mid,kl,kr);
        else if(kl > mid) return sum(p<<1|1,mid+1,r,kl,kr);
        else return sum(p<<1,l,mid,kl,mid) + sum(p<<1|1,mid+1,r,mid+1,kr);
        }
    }t[2];//0 records left ,1 records right
    
    void work()
    {
        ll tot1 = 0,tot2 = 0;
        sort(loc+1,loc+1+tot);
        rep(i,1,tot>>1) tot1 += loc[i];
        rep(i,(tot>>1)+1,tot) tot2 += loc[i];
        printf("%lld
    ",ans + tot2 - tot1);
    }
    
    void solve()
    {
        sort(d+1,d+1+cnt);
        sort(loc+1,loc+1+tot);
        len = unique(loc+1,loc+1+tot) - loc - 1;
        rep(i,1,cnt)
        {
        d[i].l = lower_bound(loc+1,loc+1+len,d[i].l) - loc;
        d[i].r = lower_bound(loc+1,loc+1+len,d[i].r) - loc;
        }
        rep(i,1,cnt) t[1].modify(1,1,len,d[i].l,1),t[1].modify(1,1,len,d[i].r,1);
        rep(i,1,cnt)
        {
        t[0].modify(1,1,len,d[i].l,1),t[0].modify(1,1,len,d[i].r,1);
        t[1].modify(1,1,len,d[i].l,-1),t[1].modify(1,1,len,d[i].r,-1);
        int r1 = t[0].find(1,1,len,i),r2 = t[1].find(1,1,len,cnt-i);
        ll d1 = t[0].size(1,1,len,1,r1) * loc[r1] - t[0].sum(1,1,len,1,r1) + t[0].sum(1,1,len,r1,len) - t[0].size(1,1,len,r1,len) * loc[r1];
        ll d2 = t[1].size(1,1,len,1,r2) * loc[r2] - t[1].sum(1,1,len,1,r2) + t[1].sum(1,1,len,r2,len) - t[1].size(1,1,len,r2,len) * loc[r2];
        minn = min(minn,d1+d2);
        }
        printf("%lld
    ",minn + ans);
    }
    int main()
    {
        k = read(),n = read();
        rep(i,1,n)
        {
        scanf("%s",s1),s = read();
        scanf("%s",s2),ter = read();
        if(s > ter) swap(s,ter);
        if(s1[0] == s2[0]) ans += ter-s;
        else ans++,loc[++tot] = s,loc[++tot] = ter,d[++cnt].l = s,d[cnt].r = ter;
        }
        if(!cnt)
        {
        printf("%lld
    ",ans);
        exit(0);
        }
        if(k == 1) work();
        else solve();
        return 0;
    }
  • 相关阅读:
    用ElasticSearch和Protovis实现数据可视化
    分布式搜索elasticsearch配置文件详解
    PHP ElasticSearch的使用
    在Windows .NET平台下使用Memcached
    升級 Centos 6.5 的 php 版本
    elasticsearch-查询基础篇
    Elasticsearch 权威指南
    [转] Mongoose初使用总结
    [转] 深入浅出mongoose-----包括mongoose基本所有操作,非常实用!!!!!
    [转] mongodb下载、安装、配置与使用
  • 原文地址:https://www.cnblogs.com/captain1/p/9682362.html
Copyright © 2011-2022 走看看