DTOJ3702 月读(tsukuyomi)

题目

题目描述

有些时候,出题人真的不想写背景(???)
总而言之,月读现在有一棵大小为$N$,树上每条边上有一个数字,月读有$M$次询问,每次询问一对$(x,y)$,你需要回答从$x$到$y$的路径上的数字重新排列能否形成一个回文序列,若可行输出Yes,否则输出No
月读为了加快您的读入,每次询问的$x,y$是通过某种方式生成的,为了加快您的输出,你只需要最后输出回答Yes的个数和即可

输入格式

第一行:两个整数$N,M$
接下来$N-1$行:三个整数$u_i,v_i,w_i$​,描述一条边$(u_i,v_i)$与边上的数字$w_i$
接下来一行$A_1,B_1$
$M$个询问以如下方式生成
$x_i=A_i \% n+1,y_i=B_i \% n+1$
$A_i=A_{i-1} \times 666073 \% (10^9+7)$
$B_i=B_{i-1} \times 233 \% 998244353$

输出格式

一行一个数字,代表回答Yes的个数

样例

样例输入

1
2
3
4
5
4 1
1 2 1
2 3 1
1 4 2
2 3

样例输出

1
1

数据范围与提示

对于此题有六个测试点:
A($10$分)$N,M \leqslant 2000$
B($23$分)$N,M \leqslant 10^5,u_i=v_i+1$
C($15$分)$N,M \leqslant 10^5$
D($15$分)$N,M \leqslant 10^6,w_i \leqslant 30$
E($17$分)$N,M \leqslant 10^6$
F($20$分)$N \leqslant 10^6,M \leqslant 10^7$
对于所有的$wi \leqslant n$

题解

如果重新排列能形成一个回文序列的话,那么满足出现的次数是奇数的数字最多只能有一个
所以我们可以对每一种边权进行哈希赋值,和$0$一起存入哈希表中
接着,我们记$Xor_i$为根到$i$点的边权异或和
那么,如果询问的点为$x,y$,只要$f_x\land f_y$在哈希表里出现过,回答就是$Yes$
注意:如果你在DTOJ上提交,建议你不要使用C++11(NOI),使用C++11,否则可能会超时
附上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<cstdio>
int n,m,Tot,tot,cnt,Head[1000010],Nxt[1000010],head[1000010],to[2000010],ver[2000010],nxt[2000010],dfn[1000010];
unsigned long long POW[1000010],pow[2000010],Ver[1000010];
inline int read(){
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
void Add(unsigned long long x)
{
int y=x%1000007;
Nxt[++Tot]=Head[y],Head[y]=Tot,Ver[Tot]=x;
}
int Find(unsigned long long x)
{
int y=x%1000007;
for(int i=Head[y];i;i=Nxt[i]) if(Ver[i]==x) return 1;
return 0;
}
void add(int u,int v,int w)
{
nxt[++tot]=head[u],head[u]=tot,to[tot]=v,ver[tot]=w;
}
void dfs(int x,int fa,unsigned long long Pow)
{
dfn[x]=++cnt,pow[cnt]=Pow;
for(int i=head[x];i;i=nxt[i]) if(to[i]!=fa) dfs(to[i],x,POW[ver[i]]),pow[++cnt]=POW[ver[i]];
}
int main()
{
n=read(),m=read(),POW[0]=1,Add(0);
for(int i=1;i<=n;i++) POW[i]=POW[i-1]*793999,Add(POW[i]);
for(int i=1,u,v,w;i<n;i++) u=read(),v=read(),w=read(),add(u,v,w),add(v,u,w);
dfs(1,0,(unsigned long long)0);
for(int i=2;i<=cnt;i++) pow[i]^=pow[i-1];
int a,b,ans=0;
a=read(),b=read();
for(int i=1,x,y;i<=m;i++)
x=a%n+1,y=b%n+1,a=666073ll*a%1000000007,b=233ll*b%998244353,ans+=Find(pow[dfn[x]]^pow[dfn[y]]);
printf("%d",ans);
}