题目描述
给定一棵
n
n
n 个节点的树,点的标号为
1
…
n
1 \dots n
1…n ,边有边权。
记
d
(
u
,
v
)
d(u, v)
d(u,v) 为
u
u
u 到
v
v
v 的路径上边的权值和,对于每个节点
u
u
u ,你需要给出一个
m
m
m 维向量
p
u
=
{
p
u
,
1
,
…
,
p
u
,
m
}
p_u = \{p_{u,1}, \dots, p_{u,m}\}
pu={pu,1,…,pu,m} ,使得对于任意点对
u
,
v
u,v
u,v ,满足
d
(
u
,
v
)
=
m
a
x
{
∣
p
u
,
i
−
p
v
,
i
∣
}
d(u, v) = max\{|p_{u,i} − p_{v,i}|\}
d(u,v)=max{∣pu,i−pv,i∣} 。
数据范围
2 ≤ n ≤ 1000 2 \le n \le 1000 2≤n≤1000 ; 1 ≤ w i ≤ 1 0 5 1 \le w_i \le 10^5 1≤wi≤105 ; m ≤ 16 m \le 16 m≤16
题解
怎么想到点分的不知道。
考虑一个点分中心 r o o t root root ,把子树尽量按 s i z e size size 均分成两部分,然后使用一维向量,将 A A A 集合的值设为 d e e p deep deep , B B B 集合设为 − d e e p -deep −deep , r o o t root root 设为 0 0 0 ,然后将 r o o t root root 分别加入两边集合继续递归下去得到两个不同的向量,然后将其中一个向量平移成另一个向量即可,要把向量上所属集合也要平移。
代码
#include <bits/stdc++.h>
using namespace std;
const int N=1005,M=N<<1;
int n,hd[N],V[M],nx[M],W[M],t,S[N],sz[N],rt;
int o,vis[N],b[N],son[N],f[N][18],g[18][18];
bool cmp(int x,int y){return sz[x]>sz[y];}
void add(int u,int v,int w){
nx[++t]=hd[u];V[hd[u]=t]=v;W[t]=w;
}
void Sz(int x,int fr){
sz[x]=1;
for (int i=hd[x];i;i=nx[i])
if (V[i]!=fr && !vis[V[i]])
Sz(V[i],x),sz[x]+=sz[V[i]];
}
void Rt(int x,int fr){
son[x]=o-sz[x];
for (int i=hd[x];i;i=nx[i])
if (V[i]!=fr && !vis[V[i]])
Rt(V[i],x),son[x]=max(son[x],sz[V[i]]);
if (son[x]<son[rt]) rt=x;
}
void push(int x,int fr,int v){
vis[x]=v;
for (int i=hd[x];i;i=nx[i])
if (V[i]!=fr && !vis[V[i]])
push(V[i],x,v);
}
void clr(int x,int fr,int v){
vis[x]=0;
for (int i=hd[x];i;i=nx[i])
if (V[i]!=fr && vis[V[i]]==v)
clr(V[i],x,v);
}
void gx(int x,int fr,int v){
for (int i=v+1;i<=16;i++)
f[x][i]+=g[v][i];f[x][v]=-f[x][v];
for (int i=hd[x];i;i=nx[i])
if (V[i]!=fr && !vis[V[i]])
gx(V[i],x,v);
}
void down(int x,int fr,int v,int w){
f[x][v]=w;
for (int i=hd[x];i;i=nx[i])
if (V[i]!=fr && !vis[V[i]])
down(V[i],x,v,w+W[i]);
}
void work(int x,int v){
o=sz[x];rt=t=0;Rt(x,0);x=rt;Sz(x,0);
for (int i=hd[x];i;i=nx[i]) if (!vis[V[i]])
S[++t]=V[i],down(V[i],x,v,W[i]);
if (sz[x]<=2) return;
sort(S+1,S+t+1,cmp);int w[2]={0,0};
for (int j,i=1;i<=t;i++)
j=w[0]>w[1],w[b[S[i]]=j]+=sz[S[i]];
for (int i=hd[x];i;i=nx[i])
if (!vis[V[i]] && b[V[i]]) push(V[i],x,v);
sz[x]=w[0]+1;work(x,v+1);
for (int i=v+1;i<=16;i++) g[v][i]=f[x][i],f[x][i]=0;
for (int i=hd[x];i;i=nx[i]){
if (!vis[V[i]]) push(V[i],x,v);
else if (vis[V[i]]==v) clr(V[i],x,v);
}
sz[x]=w[1]+1;work(x,v+1);
for (int i=v+1;i<=16;i++)
g[v][i]-=f[x][i],f[x][i]+=g[v][i];
for (int i=hd[x];i;i=nx[i])
if (vis[V[i]]==v) clr(V[i],x,v);
else if (!vis[V[i]]) gx(V[i],x,v);
}
int main(){
cin>>n;son[0]=1e9;
for (int i=1,x,y,z;i<n;i++)
scanf("%d%d%d",&x,&y,&z),
add(x,y,z),add(y,x,z);
Sz(1,0);work(1,1);puts("16");
for (int i=1;i<=n;i++)
for (int j=1;j<=16;j++)
printf("%d",f[i][j]),
putchar(j<16?' ':'\n');
return 0;
}