题目
分析
从题目中可以看出,相邻节点的异或值是确定的,那么只要一个节点的值确定了,整棵树上节点的值就确定了。于是可以先确定
1
1
1号节点的值,再判断剩下的合不合法。然后发现对于
1
1
1号节点,它异或上一个数
x
x
x,相当于整棵树异或上
x
x
x。所以可以先用
d
f
s
dfs
dfs求出当
1
1
1号节点等于
0
0
0时的所有节点值,再求出符合条件的
x
x
x的个数。
于是题目就变成了求符合
(
a
i
(a_i
(ai
x
o
r
xor
xor
x
)
x)
x)
∈
\in
∈
[
l
i
,
r
i
]
[l_i,r_i]
[li,ri]的
x
x
x的个数。
然后这个问题可以用差分加离散化做。求出每个
x
i
x_i
xi的范围后,用差分求并集,输出答案即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n;
struct edge
{
int to,sum;
edge(){}
edge(int _,int __){to=_;sum=__;}
};
struct node
{
int l,r;
}a[100100];
int v[100100];
vector<edge>e[100100];
map<ll,ll>ma;
void addd(int k,int x,int y)
{
for (int i=30;i>=0;i--)
{
int bit=1<<i;
if (k&bit)
{
int head=~(bit-1);
int p=head&(k^bit^x);
ma[p]+=y;
ma[p+bit]-=y;
}
}
}
void dfs(int x,int fa)
{
for (int i=0;i<e[x].size();i++)
if (e[x][i].to!=fa)
{
v[e[x][i].to]=v[x]^e[x][i].sum;
dfs(e[x][i].to,x);
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
scanf("%d%d",&a[i].l,&a[i].r);
for (int i=1;i<n;i++)
{
int x,y,sum;
scanf("%d%d%d",&x,&y,&sum);
e[x].push_back(edge(y,sum));
e[y].push_back(edge(x,sum));
}
v[1]=0;
dfs(1,0);
for (int i=1;i<=n;i++)
{
addd(a[i].l,v[i],-1);
addd(a[i].r+1,v[i],1);
}
int ans=0,now=0,pre=0;
map<ll,ll>::iterator it;
for (it=ma.begin();it!=ma.end();it++)
{
if (now==n) ans+=it->first-pre;
now+=it->second;
pre=it->first;
}
printf("%d\n",ans);
}
后记
少数卡 l o n g long long l o n g long long的题目。之前用居然在 83 % 83\% 83%左右超时了。(也有可能姿势问题)