牛客网比赛216C-小K的疑惑-题解

题目地址【IN

写了一遍就过了,ヾ(◍°∇°◍)ノ゙凯森

题意简述

给你一棵nnn个节点的树,每条边有边权,定义dis(i,j)dis(i,j)dis(i,j)为点iiijjj的距离模222后的值,问你有多少个三元组(i,j,k)(i,j,k)(i,j,k)满足1≤i,j,k≤n1\leq i,j,k\leq n1i,j,kndis(i,j)=dis(j,k)=dis(i,k)dis(i,j)=dis(j,k)=dis(i,k)dis(i,j)=dis(j,k)=dis(i,k)

数据范围n≤1e4,0≤val≤233n\leq 1e4,0\leq val\leq 233n1e4,0val233


我们可以发现(a+b)%2=(a%2 xor b%2)(a+b)\%2=(a\%2\ xor\ b\%2)(a+b)%2=(a%2 xor b%2)

那么dis(i,j)dis(i,j)dis(i,j)就变成了i→ji\rightarrow jij的路径权值异或和。

那么,由于a xor a=0a\ xor\ a=0a xor a=0,异或是可以相消的,所以我们可以dfsdfsdfs处理一个数组d[i]d[i]d[i],表示节点iii到根(这里默认根为111号点)的路径上的异或和,那么dis(i,j)=d[i] xor d[j]dis(i,j)=d[i]\ xor\ d[j]dis(i,j)=d[i] xor d[j],原因如下图:

eg

6→16\rightarrow 161的路径上有1−2,2−3,3−4,4−61-2,2-3,3-4,4-612,23,34,46

7→17\rightarrow 171的路径上有1−2,2−3,3−5,5−71-2,2-3,3-5,5-712,23,35,57

那么将d[6] xor d[7]d[6]\ xor\ d[7]d[6] xor d[7],其中重复的边1−2,2−31-2,2-312,23就会被异或掉,然后剩下的就变成了6−4,4−3,3−5,5−7=dis(6,7)6-4,4-3,3-5,5-7=dis(6,7)64,43,35,57=dis(6,7)了。

所以dis(i,j)=d[i] xor d[j]dis(i,j)=d[i]\ xor\ d[j]dis(i,j)=d[i] xor d[j]

那么由于只有d[i]=d[j]=d[k]d[i]=d[j]=d[k]d[i]=d[j]=d[k]的时候才会成为一个合法的三元组,而d[i]d[i]d[i]的值只有0,10,10,1,所以统计一下个数,我们令cnt0,cnt1cnt_0,cnt_1cnt0,cnt1分别为0,10,10,1的个数,那么答案就为(cnt0)3+(cnt1)3(cnt_0)^3+(cnt_1)^3(cnt0)3+(cnt1)3(由于i,j,ki,j,ki,j,k可以交换顺序,所以方案数为个数的三次方)。

代码非常简单:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=1e5+10;

struct ss{
	int to,last,len;
	ss(){}
	ss(int a,int b,int c):to(a),last(b),len(c){}
}g[M<<1];
int head[M],cnt;
void add(int a,int b,int c){
	g[++cnt]=ss(b,head[a],c&1);head[a]=cnt;
	g[++cnt]=ss(a,head[b],c&1);head[b]=cnt;
}
ll rec[2];
void dfs(int a,int b,int val){
	++rec[val];
	for(int i=head[a];i;i=g[i].last){
		if(g[i].to==b) continue;
		dfs(g[i].to,a,val^g[i].len);
	}
}
ll cude(ll a){return a*a*a;}
int a,b,c,n;
int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		scanf("%d%d%d",&a,&b,&c);
		add(a,b,c);
	}
	dfs(1,0,0);
	printf("%lld\n",cude(rec[0])+cude(rec[1]));
	return 0;
}

转载于:https://www.cnblogs.com/VictoryCzt/p/10053390.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值