SDOI2017 天才黑客

2022-03-19 20:28:14 字數 1495 閱讀 1761

我們不妨思考一下,兩個串的\(lcp\)的長度在\(trie\)樹上是什麼?

對應點的\(lca\)的深度。

然後就可以想到把邊看成點,然後把邊與邊之間連邊,點權看成這條邊經過所需要的時間。

但是這樣子連邊是\(o(m^2)\)的,不夠優秀。

我們需要進一步優化。

考慮兩個點之間的\(lcp\)可以用什麼來代替?

\(sa\)裡面的\(height\)對吧。

所以此時我們就是\(\min_^rh_i\)。

此時就不難想到用前字尾優化連邊了。

/*

mail: [email protected]

author: mleautomaton

this code is made by mleautomaton

*/#include#include#include#include#include#include#include#include#includeusing namespace std;

#define ll long long

#define re register

#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)

inline int gi()

while(ch>='0' && ch<='9')

return f*sum;

}const int n=1000010;

int front[n],cnt,dfn[n],f[n][20],dep[n],n,m,k,d[n],val[n],pl[n],sl[n],pr[n],sr[n];

struct nodee[n<<1];

vectorin[n],out[n];

int dis[n],vis[n],time,que[n],all;

void add(int u,int v,int w);front[u]=cnt;}

typedef pairpii;

priority_queue,greater>q;

#define mp make_pair

void dfs(int u)

}int lca(int x,int y)

bool cmp(int a,int b)

if(que[i]>0)

else

} for(int i=1;idis[u]+e[i].w+val[v])

} }while(!q.empty())q.pop();

}void solve()

for(int i=1;idfs(1);

memset(front,0,sizeof(front));cnt=0;

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

dijkstra();

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

}int main()

SDOI2017 天才黑客

這題太神了。先模claris 大神的題解。首先我們要將邊轉換為點。如果暴力連邊就會有 m 2 的邊,於是我們考慮優化建圖。難點在於快速得到兩個邊的串的 lcp 也就是 trie 樹上的 lca 我們將一堆點按 dfs 序排序,然後 a 到 b 的 lca 就是排序後 min 這裡的 min 是深度最...

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...