【2019杭州集训12.09】向量

Description

  • 给定一棵 nn 个节点的树,点的标号为 1..n1..n,边有边权。
  • d(u,v)d(u, v)uuvv 的路径上边的权值和,对于每个节点 uu,你需要给出一个 mm
    向量 pu=pu ={ pu,1,..,pu,mp_{u,1}, .., p_{u,m} }。
    使得对于任意点对 u,vu,v,满足 d(u,v)=maxpu,ipv,id(u, v) = max{|p_{u,i} − p_{v,i}|}
    在这里插入图片描述
  • n<=1000n<=1000

Solution

  • 刚开始看错题意了QwQ,没有注意到向量的位置是对应的。
  • 暴力的构造一个答案的方法就是直接以每一个点为根多一维,每一个点在这一维的值即为它的深度。
  • 我们可以通过调整根的选择和正负号来使得维数最少。
  • 点分治。点分治的每一层就是每一维,最后的维数就是层数。
  • 每一次将儿子分成尽量均匀的两块,一边是 dep-dep,一边是depdep,这样子这两边互相就可以满足了,这样就只用考虑子问题了。
  • 不同的两块可能在这一维有共点。直接给边赋权值,从一个点开始统一就好了。
  • 注意到会不会子问题的答案之间互相影响会不会超过两两的距离。实际上是每条边的*+1或-1加在一起,肯定不会超过全部正或全部负。
  • 那么一共有多少层呢?
  • 结论是每一次至少分n/3.
  • 首先重儿子的大小<=n/2,如果最大重儿子sz>=n/3,得证。如果最大重儿子sz<n/3,那么每多一个儿子在n/3以内,最后平均的大小是不会超过2*n/3的,得证。
  • 每一次大小至少乘2/3,对于1000正好有16层。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define maxn 1005
using namespace std;

int n,i,j,k,x,y,z;
int em,e[maxn*2],nx[maxn*2],ls[maxn],ec[maxn*2],h[20][maxn*2];
int bz[maxn],ans[20][maxn];

void insert(int x,int y,int z){
	em++; e[em]=y; nx[em]=ls[x]; ls[x]=em; ec[em]=z;
	em++; e[em]=x; nx[em]=ls[y]; ls[y]=em; ec[em]=z;
}

int g,sz[maxn],All;
void Getg(int x,int p){
	int mx=0; sz[x]=1;
	for(int i=ls[x];i;i=nx[i]) if (e[i]!=p&&!bz[e[i]])
		Getg(e[i],x),sz[x]+=sz[e[i]],mx=max(mx,sz[e[i]]);
	mx=max(mx,All-sz[x]);
	if (mx<=All/2) g=x;
}

void Getsz(int x,int p){
	sz[x]=1;
	for(int i=ls[x];i;i=nx[i]) if (e[i]!=p&&!bz[e[i]])
		Getsz(e[i],x),sz[x]+=sz[e[i]];
}

int tot;
struct node{int x,sz;} A[maxn];
int cmp(node a,node b){return a.sz>b.sz;}

int nowdep,maxdep;
void Cover(int x,int p,int k){
	for(int i=ls[x];i;i=nx[i]) if (!bz[e[i]]){
		if (e[i]==p) h[nowdep][i]=-k*ec[i],h[nowdep][i^1]=k*ec[i];
		else Cover(e[i],x,k);
	}
}

int d0[20][maxn],d1[20][maxn];
void Doit(int now,int all,int depth){
	if (all==1) {bz[now]=1;return;}
	int i; maxdep=max(maxdep,depth);
	All=all,Getg(now,0);
	Getsz(g,0);
	for(tot=0,i=ls[g];i;i=nx[i]) if (!bz[e[i]])
		tot++,A[tot].x=e[i],A[tot].sz=sz[e[i]];
	sort(A+1,A+1+tot,cmp);
	int sum0=0,sum1=0; nowdep=depth;
	d0[depth][0]=d1[depth][0]=0;
	for(i=1;i<=tot;i++) if (sum0<sum1)
		sum0+=A[i].sz,d0[depth][++d0[depth][0]]=A[i].x,Cover(A[i].x,g,1);
	else sum1+=A[i].sz,d1[depth][++d1[depth][0]]=A[i].x,Cover(A[i].x,g,-1);
	
	int nowg=g;
	if (all-sum0>2){
		for(i=1;i<=d0[depth][0];i++) bz[d0[depth][i]]=1;
		Doit(nowg,all-sum0,depth+1);
		for(i=1;i<=d0[depth][0];i++) bz[d0[depth][i]]=0;
	}
	
	if (all-sum1>2){
		for(i=1;i<=d1[depth][0];i++) bz[d1[depth][i]]=1;
		Doit(nowg,all-sum1,depth+1);
		for(i=1;i<=d1[depth][0];i++) bz[d1[depth][i]]=0;
	}
}

void DFS(int x,int p,int D,int tp){
	ans[tp][x]=D;
	for(int i=ls[x];i;i=nx[i]) if (e[i]!=p)
		DFS(e[i],x,D+h[tp][i],tp);
}

int main(){
	freopen("ceshi.in","r",stdin);
	freopen("ceshi.out","w",stdout);
	scanf("%d",&n);
	for(em=1,i=1;i<n;i++) 
		scanf("%d%d%d",&x,&y,&z),insert(x,y,z);
	Doit(1,n,1);
	for(i=1;i<=maxdep;i++) DFS(1,0,0,i);
	printf("%d\n",maxdep);
	for(j=1;j<=n;j++,printf("\n")) for(i=1;i<=maxdep;i++) printf("%d ",ans[i][j]);
}

posted @ 2019-12-10 09:52  Deep_Thinking  阅读(113)  评论(0编辑  收藏  举报