這道題一開始在想可以列舉每個點對,嘗試刪除其間的邊,因為有o(
n2) 個點對,所以要o(
1)更新答案
後來發現,因為是樹,所以只有o(
n)個點對是有用的(這麼顯然的結論一開始沒發現,看來還是我太弱了),然後就可以每次o(
n)判斷
首先定義在一棵樹
x 中,對於點y,
f(x,
y)等於以
y 為根的有根樹,(帶權)深度最大的點的深度
對於一條邊連線的兩顆子樹a、
b ,分別求出其直徑長度da
和db ,再分別求出f(
a,x)
與f(b
,y) 最小的點,然後記該邊的值為ma
x(d_a
, d_b,f
(a,x
)+f(
b,y)
+dis
),其中di
s 為該邊的長度
在所有邊的值取出最小的,就是答案。
對於一棵樹,如何求出f(
a,x)
最小的x ?
x就是直徑中點,當直徑的邊數為偶數是分類討論一下就好了。
為什麼x
一定就是直徑中點?
證明:如果
x不在直徑上,那麼由直徑的性質可得直徑上離
x 最近的點
z一定比
x 更優。 如果x
在直徑上,那麼f(
a,x)
就是x 到直徑兩端點距離的較大者,顯然
x為中點時最小
因為總共有o(
n)條邊,找直徑也是o(
n),所以整個演算法的複雜度就是o(
n2) ,但找直徑的常數較大,所以我加了個強力剪枝:只嘗試計算原樹直徑上的邊。如果刪的邊不在直徑上,那麼對答案肯定沒影響。
可是,當原樹為鏈時,剪枝就失效了,所以我對於鏈特判了一下,沒有重新找直徑。
最後,我去bzoj上交了一發,好像是rank2.rank1怎麼那麼快?
#include
#include
#include
#include
using
namespace
std;
typedef
unsigned
int ui;
struct edgex;
const
int n=5010;
vector
g[n];
int n,i,u,v,d,ans,y,z,a[n],w,j,ff,sss,ttt,c[n],ww,cc[n],ss,tt,aa[n];
bool b[n],bb[n];
ui k;
void dfs1(int x,int dep,int fa)
void dfs2(int x,int dep,int fa)
bool dfs3(int x,int dep,int fa)
inline
int got(int u)
return y;
}int main());
g[v].push_back((edge));
}ans=1
<<30;
dfs1(u,d=0,0);
dfs2(v,y=0,w=0);
dfs3(v,0,0);
for(i=1,ww=w;i<=w;++i)cc[i]=c[i],aa[i]=a[i];
if(w==n)
y=a[n]-a[tt];
for(j=tt;j<=n;++j)
if(a[j]-a[tt]<=y>>1 && a[j+1]-a[tt]>=y>>1)
ans=min(ans,max(max(a[ss],a[n]-a[tt]),ff+aa[i]-aa[i-1]));
b[i]=0;
}return
printf("%d\n",ans),0;
}for(i=2;i<=ww;++i)
return
printf("%d\n",ans),0;
}
洛谷P3761 TJOI2017 城市
從加里敦大學城市規劃專業畢業的小明來到了乙個地區城市規劃局工作。這個地區一共有ri座城市,1條高速公路,保證了任意兩運城市之間都可以通過高速公路相互可達,但是通過一條高速公路需要收取一定的交通費用。小明對這個地區深入研究後,覺得這個地區的交通費用太貴。小明想徹底改造這個地區,但是由於上司給他的資源有...
題解 P3761 TJOI2017 城市
update 2020 7 15 優化了一下 markdown 的用法,增加了前面的題目描述。從加里敦大學城市規劃專業畢業的小明來到了乙個地區城市規劃局工作。這個地區一共有 n 座城市,n 1 條高速公路,保證了任意兩運城市之間都可以通過高速公路相互可達,但是通過一條高速公路需要收取一定的交通費用。...
洛谷P3758 TJOI2017 可樂
加里敦星球的人們特別喜歡喝可樂。因而,他們的敵對星球研發出了乙個可樂機械人,並且放在了加里敦星球的1號城市上。這個可樂機械人有三種行為 停在原地,去下乙個相鄰的城市,自爆。它每一秒都會隨機觸發一種行為。現 在給加里敦星球城市圖,在第0秒時可樂機械人在1號城市,問經過了t秒,可樂機械人的行為方案數是多...