1. 程式人生 > 實用技巧 >聯賽模擬測試9 C. 小奇的倉庫(warehouse)

聯賽模擬測試9 C. 小奇的倉庫(warehouse)

題目描述



分析

\(m=0\) 是顯然的換根 \(dp\)
\(m\) 不為\(0\),沿用換根\(dp\)思路
m的範圍很小,加上異或是位運算
先任選一個根,\(dfs\)求出 到每個點的距離之和 和 距離最後四位為\(0 \sim 15\)的方案數
\(m=0\)時差不多,隨便搞一下就能寫出換根的變化量

程式碼

#include<cstdio>
#include<cstring>
inline int read(){
	int x=0,fh=1;
	char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxm=1e6+5,maxn=1e5+5;
int head[maxm],tot=1;
struct asd{
	int to,next,val;
}b[maxm];
void ad(int aa,int bb,int cc){
	b[tot].to=bb;
	b[tot].next=head[aa];
	b[tot].val=cc;
	head[aa]=tot++;
}
int n,m,f[maxn],g[maxn],fcnt[maxn][16],gcnt[maxn][16],siz[maxn],zy[50];
void debug(int now){
	printf("begin-----debug\n");
	printf("--------------------\n");
	printf("g陣列 節點編號 %d\n",now);
	for(int i=0;i<=15;i++){
		if(gcnt[now][i])printf("長度:%d 數量:%d\n",i,gcnt[now][i]);
	}
	printf(">16的長度 %d\n",g[now]);
	printf("f陣列 節點編號 %d\n",now);
	for(int i=0;i<=15;i++){
		if(fcnt[now][i])printf("長度:%d 數量:%d\n",i,fcnt[now][i]);
	}
	printf(">16的長度 %d\n",f[now]);
	printf("end-----debug\n\n\n");
}
#define findbug printf("當前節點:%d 父親節點:%d 兒子節點:%d\n",now,fa,u)
void dfs(int now,int fa){
	siz[now]=1;
	for(int i=head[now];i!=-1;i=b[i].next){
		int u=b[i].to;
		if(u==fa) continue;
		dfs(u,now);
		int cs=b[i].val;
		cs=(cs>>4);
		cs=(cs<<4);
		g[now]+=g[u]+cs*siz[u];
		cs=(b[i].val&15);
		for(int j=0;j<=30;j++){
			zy[j]=0;
		}
		for(int j=0;j<=15;j++){
			int nval=j+cs;
			zy[nval]+=gcnt[u][j];
		}
		zy[cs]++;
		for(int j=0;j<=30;j++){
			if(j<=15){
				gcnt[now][j]+=zy[j];
			} else {
				gcnt[now][j-16]+=zy[j];
				g[now]+=zy[j]*16;
			}
		}
		siz[now]+=siz[u];
	}
}
void dfs2(int now,int fa){
	if(now==1){
		f[now]=g[now];
		for(int i=0;i<=15;i++){
			fcnt[now][i]=gcnt[now][i];
		}
	}
	for(int i=head[now];i!=-1;i=b[i].next){
		int u=b[i].to;
		if(u==fa) continue;
		int cs=b[i].val;
		cs=(cs>>4);
		cs=(cs<<4);
		f[u]=f[now]-g[u]-siz[u]*cs;
		f[u]+=(n-siz[u])*cs;
		cs=(b[i].val&15);
		for(int j=0;j<=30;j++){
			zy[j]=0;
		}
		for(int j=0;j<=15;j++){
			int nval=j+cs;
			zy[nval]+=gcnt[u][j];
		}
		for(int j=0;j<=30;j++){
			if(j<=15){
				fcnt[u][j]=fcnt[now][j]-zy[j];
			} else {
				fcnt[u][j-16]-=zy[j];
				f[u]-=zy[j]*16;
			}
		}
		fcnt[u][cs]--;
		for(int j=0;j<=30;j++){
			zy[j]=0;
		}
		for(int j=0;j<=15;j++){
			int nval=j+cs;
			zy[nval]+=fcnt[u][j];
		}
		zy[cs]++;
		for(int j=0;j<=30;j++){
			if(j<=15){
				fcnt[u][j]=gcnt[u][j]+zy[j];
			} else {
				fcnt[u][j-16]+=zy[j];
				f[u]+=zy[j]*16;
			}
		}
		f[u]+=g[u];
		dfs2(u,now);
	}
}
int main(){
	freopen("warehouse.in","r",stdin);
	freopen("warehouse.out","w",stdout);
	memset(head,-1,sizeof(head));
	n=read(),m=read();
	int aa,bb,cc;
	for(int i=1;i<n;i++){
		aa=read(),bb=read(),cc=read();
		ad(aa,bb,cc);
		ad(bb,aa,cc);
	}
	dfs(1,0);
	dfs2(1,0);
	for(int i=1;i<=n;i++){
		int nans=0;
		for(int j=0;j<=15;j++){
			nans=(nans+(j^m)*fcnt[i][j]);
		}
		printf("%d\n",f[i]+nans);
	}
	return 0;
}