1. 程式人生 > >小奇的倉庫(樹形DP)

小奇的倉庫(樹形DP)

「題目背景」

小奇採的礦實在太多了,它準備在喵星系建個礦石倉庫。令它無語的是,喵星系的貨運飛船引擎還停留在上元時代!

「問題描述」

喵星系有n個星球,星球以及星球間的航線形成一棵樹。

從星球a到星球b要花費[dis(a,b) Xor M]秒。(dis(a,b)表示ab間的航線長度,Xor為位運算中的異或)

為了給倉庫選址,小奇想知道,星球i(1<=i<=n)到其它所有星球花費的時間之和。

「輸入格式」

第一行包含兩個正整數n,M。
接下來n-1行,每行3個正整數a,b,c,表示a,b之間的航線長度為c。

「輸出格式」

n行,每行一個整數,表示星球i到其它所有星球花費的時間之和。

「樣例輸入」

4 0

1 2 1

1 3 2

1 4 3

「樣例輸出」

6

8

10

12

「資料範圍」

序號   N    M

 1    6    0

 2   100   5

 3  2000   9

 4  50000  0

 5  50000  0

 6  50000  1

 7  50000  6

 8  100000 10

 9  100000 13

 10 100000 15

保證答案不超過2*10^9

下面一段話是出題人神祕而不失優雅的題解

演算法1:

不會寫函式的小夥伴們,我們只需要寫個floyd,就有10分啦!

演算法2:

在演算法1的基礎上,我們對每條邊處理一下xor,就有20分啦!

演算法3:

簡單的樹形DP,或者你會nlogn的dij,處理完每個點到其它點的最短路後再加上xor,那麼這樣就有30分啦!

演算法4:

第4、5個點無需xor,那麼我們樹形DP掃一個節點與其它所有節點的路徑長度之和,可以合併資訊,最終均攤O(1),50分到手。

演算法5:

第6個點xor 1,那麼我們樹形DP到一個點時記錄有多少個0,多少個1,然後每當一條路徑到2,那部分就再記錄一個值,60分到手。

演算法6:

如果你第6個點都過了,卻沒有滿分,笨死啦!

一樣的嘛,就是原來的“0”、“1”、大於等於2變成了0~16麼~~

 


 

下面是自己的話:

 既然是棵樹,又要快速地求每個點的值,那一定是樹形DP加上換根的操作啦~

但是異或m要怎麼處理呢?可以觀察資料規模,發現m最大最大也就15,換成二進位制數也就是 1111,所以發現異或m最多隻會對數字的後面4位造成影響(異或0甚至無法造成什麼影響)

於是愉快地寫出DP陣列 f[i]sz[i][0~15]

 f表示此時以i為根的子樹到i節點的距離之和(減去後綴後的和)

  sz表示此時距離以j為字尾的共有幾個

每一次向根節點方向轉移時會加上一條邊的長度,此時不同字尾距離的字尾會發生相應改變,然後更新父親相應字尾的sz值。

然後f裡統計的距離總和是抹掉所有後綴後的總和,即不考慮字尾的貢獻。如有一個距離是 10111(2),抹去長度為2的字尾後就只剩下10100,然後將這個結果加到f數組裡,到最後根節點統計最終答案時再考慮每個字尾的貢獻,此時的sz陣列就派上用場了(具體看程式碼)

還有一點,就是最後要把答案減去m,因為統計字尾貢獻時,多加了自己到自己的距離(本來為0,xor m 後變成了m)。

程式碼如下

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<algorithm>
  6 
  7 #define For(i,a,b) for(register int i=a;i<=b;++i)
  8 #define Re register
  9 #define Pn putchar('\n')
 10 #define inf 0x7f7f7f
 11 #define llg long long
 12 using namespace std;
 13 const int N=1e5+10;
 14 int sz[N][17];
 15 int head[N],nxt[N*2],v[N*2],cnt=1;
 16 llg w[N*2],z,fn[N],f[N];
 17 int n,m,x,y,ct,tot;
 18 
 19 inline void read(int &v){
 20     v=0;
 21     char c=getchar();
 22     while(c<'0'||c>'9')c=getchar();
 23     while(c>='0'&&c<='9')v=v*10+c-'0',c=getchar();
 24 }
 25 inline void read(llg &v){
 26     v=0;
 27     char c=getchar();
 28     while(c<'0'||c>'9')c=getchar();
 29     while(c>='0'&&c<='9')v=v*10+c-'0',c=getchar();
 30 }
 31 void write(llg x){
 32     if(x>9)write(x/10);
 33     int xx=x%10;
 34     putchar(xx+'0');
 35 }
 36 
 37 void add(int ux,int vx,llg wx){
 38     cnt++;
 39     nxt[cnt]=head[ux]; head[ux]=cnt; v[cnt]=vx; w[cnt]=wx;
 40     cnt++;
 41     nxt[cnt]=head[vx]; head[vx]=cnt; v[cnt]=ux; w[cnt]=wx;
 42 }
 43 
 44 void DFS1(int x,int fa){
 45     sz[x][0]=1;  
 46     for(Re int i=head[x];i;i=nxt[i]){
 47         int vv=v[i];
 48         if(vv==fa)continue;
 49         DFS1(vv,x);
 50         f[x]+=f[vv];
 51         For(j,0,tot){
 52             int Nsm=j+w[i];
 53             int Nst=Nsm & ct;
 54             sz[x][Nst]+=sz[vv][j];
 55             f[x]+=sz[vv][j]*(Nsm-Nst);
 56         }
 57     }
 58 }
 59 int Bsz[N][20];
 60 void DFS2(int x,int fa){   //換根 
 61     fn[x]=f[x];
 62     For(st,0,tot){
 63         fn[x]+=(st^m)*sz[x][st];
 64     }
 65     For(st,0,tot)Bsz[x][st]=sz[x][st];
 66     llg Bf=f[x];
 67     
 68     for(Re int i=head[x];i;i=nxt[i]){
 69         int vv=v[i];
 70         if(vv==fa)continue;
 71         
 72         int Nsm,Nst;
 73          
 74         For(st,0,tot){
 75             Nsm =st+w[i];
 76             Nst=Nsm&ct;
 77             sz[x][Nst]-=sz[vv][st];
 78             f[x]-=sz[vv][st]*(Nsm-Nst);
 79         }
 80     
 81         f[vv]=f[x];
 82         For(st,0,tot){
 83             Nsm=st+w[i];
 84             Nst=Nsm&ct;
 85             sz[vv][Nst]+=sz[x][st];
 86             f[vv]+=sz[x][st]*(Nsm-Nst);
 87         }
 88 
 89         DFS2(vv,x);
 90         
 91         f[x]=Bf;
 92         For(st,0,tot)sz[x][st]=Bsz[x][st];
 93     }    
 94 }
 95 
 96 int main(){
 97 //    freopen("warehouse.in","r",stdin);
 98 //    freopen("warehouse.out","w",stdout);
 99     read(n); read(m);
100     
101     if(m==0)ct=0,tot=0;
102     if(m==1)ct=1,tot=1;
103     if(m==5)ct=7,tot=7;
104     if(m==6)ct=7,tot=7;
105     if(m>=9)ct=15,tot=15;  //簡單粗暴的預處理 
106     
107     For(i,1,n-1){
108         read(x); read(y); read(z);
109         add(x,y,z);
110     }
111     DFS1(1,0);
112     DFS2(1,0);
113     For(i,1,n){
114          write(fn[i]-m); Pn;
115     }
116     return 0;
117 }