1. 程式人生 > >[BZOJ1150][CTSC2007]數據備份Backup

[BZOJ1150][CTSC2007]數據備份Backup

new 長度 網絡電纜 距離 priority problem urn 工作 電信

bzoj
luogu

Description

你在一家 IT 公司為大型寫字樓或辦公樓(offices)的計算機數據做備份。然而數據備份的工作是枯燥乏味的,因此你想設計一個系統讓不同的辦公樓彼此之間互相備份,而你則坐在家中盡享計算機遊戲的樂趣。已知辦公樓都位於同一條街上。你決定給這些辦公樓配對(兩個一組)。每一對辦公樓可以通過在這兩個建築物之間鋪設網絡電纜使得它們可以互相備份。然而,網絡電纜的費用很高。當地電信公司僅能為你提供K條網絡電纜,這意味著你僅能為K對辦公樓(或總計2K個辦公樓)安排備份。任一個辦公樓都屬於唯一的配對組(換句話說,這2K個辦公樓一定是相異的)。此外,電信公司需按網絡電纜的長度(公裏數)收費。因而,你需要選擇這K對辦公樓使得電纜的總長度盡可能短。換句話說,你需要選擇這 K 對辦公樓,使得每一對辦公樓之間的距離之和(總距離)盡可能小。下面給出一個示例,假定你有 5個客戶,其辦公樓都在一條街上,如下圖所示。這5個辦公樓分別位於距離大街起點 1km, 3km, 4km, 6km 和 12km 處。電信公司僅為你提供 K=2 條電纜。

技術分享圖片
上例中最好的配對方案是將第 1 個和第 2 個辦公樓相連,第 3 個和第 4 個辦公樓相連。這樣可按要求使用K=2 條電纜。第 1 條電纜的長度是 3km-1km=2km ,第 2 條電纜的長度是 6km-4km=2km。這種配對方案需要總長4km 的網絡電纜,滿足距離之和最小的要求。

sol

只有相鄰的建築才會匹配,所以是一個二分圖,且每個點的度數不超過\(2\)
直接上費用流會\(T\)
考慮一下費用流的運行過程。每一次的增廣都是從左邊的一個點出發,經過若幹條(可以是不經過)反向邊後到達一個右邊的點。由於每個點度數不超過\(2\),所以如果確定了從哪個點開始增廣,那麽增廣的路徑一定會是唯一的。

所以用堆維護一下從每個點出發的增廣路徑長度就行了。
現在考慮一條路徑增廣後對其他路徑的影響。顯然只會影響到自己的前驅和後繼,使得原本前驅後繼的增廣方式不復存在,同時也產生了一種新的增廣方式——把當前這條增廣路全部取反。所以相當於新建一個點,用鏈表維護一下即可。
復雜度\(O(n\log n)\)

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int gi(){
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}
#define pi pair<int,int>
#define mk make_pair
const int N = 2e5+5;
int n,k,tot,dis[N],lst[N],nxt[N],del[N],val[N],ans;
priority_queue<pi,vector<pi>,greater<pi> >Q;
int main(){
    freopen("backup.in","r",stdin);
    freopen("backup.out","w",stdout);
    n=gi();k=gi();tot=n-1;
    for (int i=1;i<=n;++i) dis[i]=gi(),lst[i]=i-1,nxt[i]=i+1;
    nxt[n-1]=nxt[n]=0;
    for (int i=1;i<n;++i) Q.push(mk(val[i]=dis[i+1]-dis[i],i));
    while (k--){
        while (del[Q.top().second]) Q.pop();int x=Q.top().second;Q.pop();
        ans+=val[x];del[x]=del[lst[x]]=del[nxt[x]]=1;
        if (!lst[x]) lst[nxt[nxt[x]]]=0;
        else if (!nxt[x]) nxt[lst[lst[x]]]=0;
        else{
            val[++tot]=val[lst[x]]+val[nxt[x]]-val[x];
            lst[tot]=lst[lst[x]],nxt[tot]=nxt[nxt[x]];
            if (lst[tot]) nxt[lst[tot]]=tot;
            if (nxt[tot]) lst[nxt[tot]]=tot;
            Q.push(mk(val[tot],tot));
        }
    }
    printf("%d\n",ans);
    return 0;
}

[BZOJ1150][CTSC2007]數據備份Backup