codeforces 962E Byteland, Berland and Disputed Cities 最小生成樹變形
阿新 • • 發佈:2018-12-24
題目
題意
在軸上有一堆點,這些點有三種類型型,現在要求新增一些線段把這些點連起來,使得如果去掉型別點,剩下的點都是聯通的。如果去掉型別的點,剩下的點也是聯通的,求最小的邊長度總和。
題解
如果我們單單隻看去掉型別的點的時候,這道題毫無疑問是一道最小生成樹的題目,實際上也並不需要用一些最小生成樹的做法來做,只需要按順序掃一遍就好了。
但這個題不是,它要求這個圖去掉型別的點之後,都仍舊是最小生成樹。
我們稱這張圖為二樹圖(我胡起的,只是方便後面敘述,實際上並沒有這個名字)。
那麼如何構造這個二樹圖
我們從左向右掃描所得到的點,並且假設在所掃描過的點中已經過構造好了部分二樹圖。
那麼對於我們當前正在掃描的點,該怎麼進行處理呢?
當前的點是點,那麼我們需要把這個點與前面最近的點或者最近的點相連線,這樣的話保證了去掉點之後,當前的這個點連線到了生成樹中,這樣保持了二樹圖的性質。
當前的點是點,這種情況有點複雜,因為點是不會被去掉的,所以點影響了兩種生成樹。我們這樣考慮,為了保證兩個生成樹都要連線到當前的這個點,對於去掉點得到的生成樹,想要連線,那麼我們一定要讓這個
而如果到兩顆樹最近的點都不是點(即上一個與當前點之間即有點也有點這種情況),我們首先讓當前的點連線最近的點和最近的點,在讓當前的點與前一個點相連,這樣的話,對於兩顆生成樹來說都產生了一個圈,為了保持生成樹的性質,我們需要破圈。如果我們此時破了邊,那麼獲得優勢是,保證是二樹圖,結束。如果我們不破邊,那麼我們勢必要在兩個圈中各找一個最大的
本題至此就解決了。
程式碼
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 2e5+7;
typedef long long ll;
ll B,R,mxB,mxR,P,ans;
int n;
int main(){
cin>>n;
for(int i = 1;i <= n;++i){
ll x;char c;
scanf("%lld %c",&x,&c);
x += 1e9+7;
if(c == 'B'){
if(B) ans += x - B,mxB = max(mxB,x - B);
B = x;
}
if(c == 'R'){
if(R) ans += x - R,mxR = max(mxR,x - R);
R = x;
}
if(c == 'P'){
if(B) mxB = max(mxB,x - B),ans += x-B;
if(R) mxR = max(mxR,x - R),ans += x-R;
if(P) {
ans += min(0ll,x - P - mxB - mxR);
}
B = R = P = x;
mxB = mxR = 0;
}
}
cout<<ans<<endl;
return 0;
}