题目描述
MT神牛非常喜欢出Xor的题,在WC2011的时候,MT神牛出了一道非常经典的Xor最大路径题。
Bird向MT神牛学习,思考了许多关于Xor路径的问题,有一天,Bird想到了一个问题,给出一个序列,求这个序列的连续子序列的Xor值最大。
如1 3 4 8,最大的Xor子序列当然是3 xor 4 xor 8=15了。
Bird实在太强大了,这个问题怎么能难住他呢?于是Bird又开始思考了,如果是一颗树呢,如何求出这棵带边权的树的一条最大Xor路径呢?但是谁都知道Bird实在太强大了,马上想到了解决这个问题的高效算法,但是Bird总是不愿去机房写代码,于是他把这个easy的问题,交给了你,希望你能尽快帮他写完代码。
输入
第一行,一个整数N,表示一颗树有N个节点,接下来N-1行,每行三个整数a,b,c表示节点a和节点b之间有条权值为c的边
输出
输出仅一行,即所求的带边权树的Xor最大路径。
样例输入
4
1 2 3
1 3 4
1 4 7
样例输出
7
提示
【数据规模】
对于40%的数据,数据退化为一条链
除上述的40%的数据外,还有10%的数据N<=1000
100%的数据满足2<=n<=100000, 1 < a,b<=N,C<=2^31-1
我们先考虑是一条链的情况:
用F[i]表示前i个点的异或和,则类似于前缀和,i到j(i<j)的异或和为F[j]xorF[i],所以对于链的情况答案为maxF[i]xorF[j]1<=i,j<=N.
然后我们考虑是树的情况:
类似于链,我们用F[i]表示根节点到i的异或和,显然i->j路径的异或和等价于F[i] xor F[j],这与链的情况无异。
所以题目就可以转化为给定N个数,求出这N个数中任意两个数xor的最大值。
具体做法:
在二进制中,越高位有1值越大,而异或运算只影响到当前位,所以越高位能异或成1就把它异或成1,于是我们将所有F[i]转为二进制当做字符串,按从高位到低位的顺序存入一颗字典树中,然后从最高位开始枚举,设当前数为x,当前枚举到二进制中第i位,x的第i位数字为j,当前在字典树中的k号节点,若k节点的j xor 1儿子存在,则当前答案的第i位为1,否则为0。时间复杂度(N*900)。
#include
#include
#include
#include
#define ll long long
using namespace std;
int n,x,y,z,tot,ans;
int a[35],head[100005],Next[200005],to[200005],len[200005],f[100005];
struct ty
{
int Next[2];
void init()
{
memset(Next,-1,sizeof(Next));
}
}p[3100005];
void dfs(int k,int pre)
{
for(int i=head[k];i!=-1;i=Next[i])
if(to[i]!=pre)
{
f[to[i]]=f[k]^len[i];
dfs(to[i],k);
}
}
void add(int x,int y,int z)
{
tot++;
Next[tot]=head[x];
to[tot]=y;
len[tot]=z;
head[x]=tot;
}
void work(int x)
{
int k=0;
while(x>0)
{
k++;
a[k]=x%2;
x=x/2;
}
for(int i=k+1;i<=31;i++) a[i]=0;
}
void update()
{
x=0;
for(int i=31;i>=1;i--)
{
int j=a[i];
if(p[x].Next[j]==-1)
{
tot++;
p[x].Next[j]=tot;
p[tot].init();
}
x=p[x].Next[j];
}
}
int query()
{
x=0;
int s=0;
for(int i=31;i>=1;i--)
{
int j=a[i]^1;
if(p[x].Next[j]==-1) j=j^1;
if((a[i]^j)==1) s=s+(1<<(i-1));
x=p[x].Next[j];
}
return s;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) head[i]=-1;
for(int i=1;iscanf("%d%d%d",&x,&y,&z);
add(x,y,z);
add(y,x,z);
}
dfs(1,0);
p[0].init();
for(int i=1;i<=n;i++)
{
work(f[i]);
update();
}
for(int i=1;i<=n;i++)
{
work(f[i]);
ans=max(ans,query());
}
cout<return 0;
}