1. 程式人生 > >LibreOJ #2012. 「SCOI2016」背單詞

LibreOJ #2012. 「SCOI2016」背單詞

pan ring har cst target cstring n) color 插入

二次聯通門 : LibreOJ #2012. 「SCOI2016」背單詞

/*
    LibreOJ #2012. 「SCOI2016」背單詞 

    Trie + 貪心

    大家都吐槽題目反人類
    可我覺得還好,畢竟見的多了
    
    不會做啊。。
    正解好巧妙
    
    考慮一下,發現一操作完全不必要,可以省去
    因為所有的字符串的後綴關系會形成一個樹

    那麽把字符串倒序插入Trie中
    建樹,每次向子樹小的一個點轉移即可
*/
#include <cstdio>
#include <algorithm>
#include 
<cstring> #define Max 100008 #define L 26 int N; char line[Max]; int trie[Max][L], T_C = 1; bool is[Max]; struct E { E *n; int to; }; E *list[Max], poor[Max], *Ta = poor; void Dfs (int now, int Father) { if (is[now]) { ++ Ta, Ta->to = now, Ta->n = list[Father], list[Father] = Ta; Father
= now; } for (int i = 0; i < L; ++ i) if (trie[now][i]) Dfs (trie[now][i], Father); } int size[Max]; void Re_Dfs (int now) { size[now] = 1; for (E *e = list[now]; e; e = e->n) Re_Dfs (e->to), size[now] += size[e->to]; } int dfn[Max], top, C, Stack[Max], Answer; inline
bool Comp (int a, int b) { return size[a] < size[b]; } void Get_Answer (int now) { dfn[now] = ++ C; int pos = top + 1; for (E *e = list[now]; e; e = e->n) Stack[++ top] = e->to; if (top < pos) return ; std :: sort (Stack + pos, Stack + top + 1, Comp); for (int i = pos; i <= top; ++ i) Get_Answer (Stack[i]), Answer += dfn[Stack[i]] - dfn[now]; top = pos - 1; } int Main () { scanf ("%d", &N); register int i, j; int Id, x, now, Len; for (i = 1; i <= N; ++ i) { scanf ("%s", line); Len = strlen (line); for (j = Len - 1, now = 1; j >= 0; -- j) { Id = line[j] - a; if (trie[now][Id] == 0) trie[now][Id] = ++ T_C; now = trie[now][Id]; } is[now] = true; } Dfs (1, 1), Re_Dfs (1), Get_Answer (1); printf ("%d", Answer); return 0; } int ZlycerQan = Main (); int main (int argc, char *argv[]) {;}

LibreOJ #2012. 「SCOI2016」背單詞