SDOI2017 天才黑客

2022-05-20 08:52:06 字數 1500 閱讀 9048

這題太神了。

先模claris 大神的題解。

首先我們要將邊轉換為點。如果暴力連邊就會有\(m^2\)的邊,於是我們考慮優化建圖。

難點在於快速得到兩個邊的串的\(lcp\),也就是\(trie\)樹上的\(lca\)。我們將一堆點按\(dfs\)序排序,然後\(a\)到\(b\)的\(lca\)就是排序後\(min\\),這裡的\(min\)是深度最小。

對於原圖上的點\(i\),我們就將所有的邊按\(dfs\)序拍好序,再複製一倍的虛點,相鄰的實點和虛點連權值為\(0\)的邊。每個實點向下乙個點對應的虛點連權值為\(dep_\)的邊。

然後還要反方向建相同的邊,不過不能建在一張圖上。

這道題中關於處理一堆點兩兩之間\(lca\)的方法值得掌握。

**:

#include#define ll long long

#define n 400005

using namespace std;

inline int get() while('0'<=ch&&ch<='9') return x*f;}

int n,m,k;

int tot,tot;

int w[n],t[n];

ll dis[n];

ll ans[n];

vectorst[n];

vectore[n];

struct road s[n*15];

int h[n],cnt;

void add(int i,int j,int c) ;h[i]=cnt;}

int id,dfn[n];

void init()

int dep[n];

int fa[n][20];

bool cmp(int a,int b)

int lca(int a,int b)

void dfs(int v)

};priority_queueq;

bool vis[n];

void dij()

} }}int main()

for(int i=1;im)

} dij();

memset(ans,0x3f,sizeof(ans));

for(int i=1;i<=n;i++)

} for(int i=2;i<=n;i++) cout<

} return 0;

}

SDOI2017 天才黑客

我們不妨思考一下,兩個串的 lcp 的長度在 trie 樹上是什麼?對應點的 lca 的深度。然後就可以想到把邊看成點,然後把邊與邊之間連邊,點權看成這條邊經過所需要的時間。但是這樣子連邊是 o m 2 的,不夠優秀。我們需要進一步優化。考慮兩個點之間的 lcp 可以用什麼來代替?sa 裡面的 he...

SDOI2017 天才黑客

題目大意 給一張有向圖,再給一顆字典樹,有向圖上的每條邊有乙個非負邊權還有乙個字典樹上的字串,從一條邊到另一條邊的代價是那條邊的邊權和這兩個字串的最長公共字首,問從1到其他點的最短路 題解一看肯定是乙個最短路問題,現在的關鍵問題是如何把這張圖建出來。我們可以列舉每個點作為兩條邊的中轉點,然後直接把每...

SDOI2017 天才黑客 虛樹 最短路

原諒我寫不出簡單題意 可以看到與 trie 樹上的字母以及 lcp 並沒有關係。以邊作為點,可以寫出乙個非常簡單的最短路 dis i min lbrace dis j dep c i v j u i rbrace 還可以建立 u 0 v 0 1,d 0 1,c 0 0 作為原點 但是惡意卡的話有 m...