1. 程式人生 > >bzoj5195 [Usaco2018 Feb]Directory Traversal

bzoj5195 [Usaco2018 Feb]Directory Traversal

奶牛Bessie令人驚訝地精通計算機。她在牛棚的電腦裡用一組資料夾儲存了她所有珍貴的檔案,比如:
bessie/
folder1/
file1
folder2/
file2
folder3/
file3
file4

只有一個“頂層”的資料夾,叫做bessie。
Bessie可以瀏覽任何一個她想要訪問的資料夾。從一個給定的資料夾,每一個檔案都可以通過一個“相對路徑”被引用。
在一個相對路徑中,符號“..”指的是上級目錄。如果Bessie在folder2中,她可以按下列路徑引用這四個檔案:

../file1
file2
../../folder3/file3
../../file4

Bessie想要選擇一個資料夾,使得從該資料夾出發,對所有檔案的相對路徑的長度之和最小。
Input

第一行包含一個整數N(2≤N≤100,000),為所有檔案和資料夾的總數量。
為了便於輸入,每個物件(檔案或資料夾)被賦予一個唯一的1至N之間的ID,其中ID 1指的是頂層資料夾。
接下來有N行。每行的第一項是一個檔案或是資料夾的名稱。名稱僅包含小寫字母a-z和數字0-9,長度至多為16個字元。
名稱之後是一個整數m。
如果m為0,則該物件是一個檔案。
如果m>0,則該物件是一個資料夾,並且該資料夾下共有m個檔案或資料夾。
在m之後有m個整數,為該資料夾下的物件的ID。
Output

輸出所有檔案的相對路徑的長度之和的最小值。注意這個值可能超過32位整數的表示範圍。
Sample Input

8
bessie 3 2 6 8
folder1 2 3 4
file1 0
folder2 1 5
file2 0
folder3 1 7
file3 0
file4 0
Sample Output

42

這個輸入樣例描述了上面給出的樣例目錄結構。
最優解是選擇folder1。從這個資料夾出發,相對路徑分別為:
file1
folder2/file2
../folder3/file3
../file4

讀懂題意就能寫
首先預處理我如果站在根目錄的情況 然後依次往下搜尋
設size[x]為x的子樹所包含的葉子節點的個數 cnt是總的葉子數目
dp[y]=dp[x]−(len[y]+1)∗size[y]+3∗(n−size[y])。複雜度O(n)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 110000
#define ll long long
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
struct node{
    int y,z,next;
}data[N<<1];
int n,num,h[N],cnt,size[N],dep[N],size1[N],len1[N];
ll dp[N],mn,dis[N];
inline void insert1(int x,int y){
    data[++num].y=y;data[num].next=h[x];h[x]=num;
    data[++num].y=x;data[num].next=h[y];h[y]=num;
}bool flag[N];
inline void dfs1(int x,int fa){
    if (flag[x]) return;
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;
        if (y==fa) continue;dfs1(y,x);size1[x]+=size1[y];dis[x]+=dis[y]; 
    }dis[x]+=size1[x]*len1[x];
}
inline void dfs(int x,int fa){
    for (int i=h[x];i;i=data[i].next){
        int y=data[i].y;if(y==fa) continue; 
        dp[y]=dp[x]-size1[y]*len1[y]+3*(cnt-size1[y]);dfs(y,x);mn=min(mn,dp[y]);
    }
}
int main(){
    //freopen("dirtraverse.in","r",stdin);
    //freopen("dirtraverse.out","w",stdout);
    n=read();
    for (int i=1;i<=n;++i){
        char op[20];scanf("%s",op);int len=strlen(op);int m=read();len1[i]=len+1;
        if (!m) ++cnt,dis[i]=len,flag[i]=size1[i]=1;while(m--){int y=read();insert1(i,y);}
    }dfs1(1,1);
    for (int i=h[1];i;i=data[i].next){
        int y=data[i].y;dis[1]-=len1[1]*size1[y];
    }
    dp[1]=dis[1];mn=dp[1];dfs(1,1);
    printf("%lld",mn);
    return 0;
}