1. 程式人生 > >小奇的倉庫

小奇的倉庫

truct iostream ans ace sin img 影響 兩個 n-1

【題目背景】
小奇采的礦實在太多了,它準備在喵星系建個礦石倉庫。令它無語的是,喵
星系的貨運飛船引擎還停留在上元時代!
【問題描述】
喵星系有 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

技術分享

首先考慮不異或

那麽我們先算出根節點1到所有點的距離和

接下來假設2是1兒子,邊為<1,2,w>,size[i]為i的子樹的大小

ans[2]=ans[1]+(n-size)*w-size*w=ans[1]+(n-2*size)*w

但本題加了異或,異或不滿足分配律,所以不能算出再異或

但我們發現m很小,最多也就2^4-1,也就是1111

異或只會影響後4位

於是設f[i][j]為i到其它點,後4位狀態為j的路徑條數

顯然列出:

f[u][0]=1

f[u][(j+w)%16]+=f[v][j]

這還只算了子樹

f[v][(j+w)%16]+=(f[u][j]-f[v][((j-w)%16+16)%16])

解釋一下,u這個點的所有f[u][j]除去v的方案再加入v,等於把v的方案

從子樹補到整顆樹

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 struct Node
 8 {
 9
int next,to,dis; 10 } edge[200001]; 11 int num,head[100001]; 12 long long ans[100001],n,m,f[100001][16]; 13 void add(int u,int v,int dis) 14 { 15 num++; 16 edge[num].next=head[u]; 17 head[u]=num; 18 edge[num].to=v; 19 edge[num].dis=dis; 20 } 21 void dfs1(int x,int pa) 22 { 23 int i,j; 24 f[x][0]=1; 25 for (i=head[x]; i; i=edge[i].next) 26 { 27 int v=edge[i].to; 28 if (v!=pa) 29 { 30 dfs1(v,x); 31 ans[x]+=ans[v]; 32 for (j=0; j<=15; j++) 33 f[x][(j+edge[i].dis)%16]+=f[v][j],ans[x]+=f[v][j]*edge[i].dis; 34 } 35 } 36 } 37 void dfs2(int x,int pa) 38 { 39 int i,j; 40 for (i=head[x]; i; i=edge[i].next) 41 { 42 int v=edge[i].to; 43 if (v==pa) continue; 44 int a[17]= {0},size=0; 45 for (j=0; j<=15; j++) 46 a[(j+edge[i].dis)%16]+=f[x][j]-f[v][((j-edge[i].dis)%16+16)%16],size+=f[v][j]; 47 ans[v]=ans[x]+(n-size*2)*edge[i].dis; 48 for (j=0; j<=15; j++) 49 f[v][j]+=a[j]; 50 dfs2(v,x); 51 } 52 } 53 int main() 54 { 55 int i,u,v,c,j; 56 cin>>n>>m; 57 for (i=1; i<n; i++) 58 { 59 scanf("%d%d%d",&u,&v,&c); 60 add(u,v,c); 61 add(v,u,c); 62 } 63 dfs1(1,0); 64 dfs2(1,0); 65 for (i=1; i<=n; i++) 66 { 67 f[i][0]--; 68 for (j=0; j<=15; j++) 69 ans[i]+=((j^m)-j)*f[i][j]; 70 printf("%lld\n",ans[i]); 71 } 72 }

小奇的倉庫