Xor路
(xor.pas/c/cpp)128MB1s
给定一棵有N个点和N-1条边的树,请你求出树中的最长路径,以及总共有多少条最长路径。
这里路径长度是用xor定义的,即若经过的边的权值为a1, a2, a3,...,an,则这条路径的总权值为 a1 xor a2 xor a3 ... xor an。
输入格式
第1行为一个正整数 N,为点的个数。
第2行至第N行,每行包含三个正整数x,y,z,表示x和y之间有一条权值为z的边。
输出格式
仅一行,包含两个数字,为最长路径的长度和条数。
样例输入
4
1 2 3
2 4 1
1 3 4
样例输出
7 1
样例解释
2-1-3 这条路径,长度为3 xor 4=7。
————————————————————————————————————————————————
首先xor满足 a&a=0
这样之后我们求两个点之间的路径就可以随便找一个点作为树的跟两个点之间的路径就是两个点到跟的路径的xor
这样问题就转换成了给你n个数求两个点亦或和最大值以及方案数
这个n^2明显会超时 但是利用xor的性质 我们可以利用tire来维护 复杂度nlogn
#include<cstdio> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int M=3e5+7; int n,x,y,vis[M],q[M]; LL l[3500007][2],h[3500007]; LL T,w,d[M],mx,ans,sum; int first[M],cnt; struct node{int to,next; LL w;}e[2*M]; void ins(int a,int b,LL w){cnt++; e[cnt].to=b; e[cnt].w=w; e[cnt].next=first[a]; first[a]=cnt;} void insert(int a,int b,LL w){ins(a,b,w); ins(b,a,w);} void spfa(){ int head=0,tail=1; q[0]=1; vis[1]=1; while(head!=tail){ int x=q[head++]; if(head>M) head=0; for(int i=first[x];i;i=e[i].next){ int now=e[i].to; if(vis[now]) continue; vis[now]=1; q[tail++]=now; d[now]=d[x]^e[i].w; if(tail>M) tail=0; } } } void insert(int num){ int x=0,now; for(int i=30;i>=0;i--){ now=(num&(1<<i))>>i; if(!l[x][now]) l[x][now]=++sum; x=l[x][now]; } h[x]++; } int find(int num){ int x=0,now; for(int i=30;i>=0;i--){ now=(num&(1<<i))>>i; if(l[x][!now]) x=l[x][!now],T+=(1<<i); else x=l[x][now]; } return h[x]; } int main() { scanf("%d",&n); for(int i=1;i<n;i++) scanf("%d %d %lld",&x,&y,&w),insert(x,y,w); spfa(); for(int i=1;i<=n;i++) insert(d[i]); for(int i=1;i<=n;i++){ T=0; int p=find(d[i]); if(T>mx) mx=T,ans=p; else if(T==mx) ans+=p; } printf("%lld %lld ",mx,ans>>1); return 0; }