【CF1775D】Friendly Spiders(建图)(质因子虚点)

SlavicG’s Favorite Problem

题面翻译

给你一棵树和两个点 a , b a,b a,b,边有边权。你可以在任意时刻从当前所在的点跳到任意除了 b b b 以外的点。求有没有方案使得从 a a a 出发,到达 b b b 时边权 xor ⁡ \operatorname{xor} xor 和为 0 0 0

1 ≤ n ≤ 1 0 5 1\le n\le 10^5 1n105

题目描述

You are given a weighted tree with $ n $ vertices. Recall that a tree is a connected graph without any cycles. A weighted tree is a tree in which each edge has a certain weight. The tree is undirected, it doesn’t have a root.

Since trees bore you, you decided to challenge yourself and play a game on the given tree.

In a move, you can travel from a node to one of its neighbors (another node it has a direct edge with).

You start with a variable $ x $ which is initially equal to $ 0 $ . When you pass through edge $ i $ , $ x $ changes its value to $ x \mathsf{XOR} w_i $ (where $ w_i $ is the weight of the $ i $ -th edge).

Your task is to go from vertex $ a $ to vertex $ b $ , but you are allowed to enter node $ b $ if and only if after traveling to it, the value of $ x $ will become $ 0 $ . In other words, you can travel to node $ b $ only by using an edge $ i $ such that $ x \mathsf{XOR} w_i = 0 $ . Once you enter node $ b $ the game ends and you win.

Additionally, you can teleport at most once at any point in time to any vertex except vertex $ b $ . You can teleport from any vertex, even from $ a $ .

Answer with “YES” if you can reach vertex $ b $ from $ a $ , and “NO” otherwise.

Note that $ \mathsf{XOR} $ represents the bitwise XOR operation.

输入格式

The first line contains a single integer $ t $ ( $ 1 \leq t \leq 1000 $ ) — the number of test cases.

The first line of each test case contains three integers $ n $ , $ a $ , and $ b $ ( $ 2 \leq n \leq 10^5 $ ), ( $ 1 \leq a, b \leq n; a \ne b $ ) — the number of vertices, and the starting and desired ending node respectively.

Each of the next $ n-1 $ lines denotes an edge of the tree. Edge $ i $ is denoted by three integers $ u_i $ , $ v_i $ and $ w_i $ — the labels of vertices it connects ( $ 1 \leq u_i, v_i \leq n; u_i \ne v_i; 1 \leq w_i \leq 10^9 $ ) and the weight of the respective edge.

It is guaranteed that the sum of $ n $ over all test cases does not exceed $ 10^5 $ .

输出格式

For each test case output “YES” if you can reach vertex $ b $ , and “NO” otherwise.

样例 #1

样例输入 #1

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

样例输出 #1

YES
NO
YES

提示

For the first test case, we can travel from node $ 1 $ to node $ 3 $ , $ x $ changing from $ 0 $ to $ 1 $ , then we travel from node $ 3 $ to node $ 2 $ , $ x $ becoming equal to $ 3 $ . Now, we can teleport to node $ 3 $ and travel from node $ 3 $ to node $ 4 $ , reaching node $ b $ , since $ x $ became equal to $ 0 $ in the end, so we should answer “YES”.

For the second test case, we have no moves, since we can’t teleport to node $ b $ and the only move we have is to travel to node $ 2 $ which is impossible since $ x $ wouldn’t be equal to $ 0 $ when reaching it, so we should answer “NO”.

核心思路

对于每个数的,对其质因子建立一个虚点,并连双向边,每个点与自己的因子入边边权为1,出边为0。

然后跑最短路即可

AC代码

#include<bits/stdc++.h>
using namespace std;
const int MMax = 2147483647;
struct edge{
	int v,w;//v 表示 去的节点,w 表示 权值。 
}; 
struct node {
    int dis, u;
    bool operator>(const node& a) const { return dis > a.dis; }
}; 
const int N = 3e5+10;
vector<edge> g[N*2];
int n,m,s,t;
int a[N*2];
priority_queue<node, vector<node>, greater<node> > q;
int dis[N*2];bool vis[N*2];
int fa[N*2];
int Maxx;
void dijk(int s){
    memset(dis,0x3f,sizeof(dis));
	dis[s] = 0;
	Maxx = dis[1];
	q.push(node{0,s});
	while(!q.empty()){
		int u = q.top().u;
		q.pop();
		if(vis[u] == 1)continue;
		vis[u] = 1;
		for(int i = 0;i < g[u].size();i++){
			int v = g[u][i].v,w = g[u][i].w;
			if(dis[v] > dis[u]+w){
				dis[v] = dis[u]+w;
				fa[v] = u;
				q.push(node{dis[v],v});
			}
		}
		
	}
	
}
void dfs(int x){
	if(x == s){
		if(x <= n)cout<<x<<" ";
	}
	else{
		dfs(fa[x]);
		if(x <= n)cout<<x<<" ";
	}
}
int ans = 0;
void dfs2(int x){
	if(x == s){
		if(x <= n){
			ans++;
		    //cout<<x<<" ";
	    }
	}
	else{
		dfs2(fa[x]);
		if(x <= n){
		    //cout<<x<<" ";
		    ans++;
	    }
	}
}

int main() {
	cin>>n;
	for(int i = 1;i <= n;i++){
		cin>>a[i];
		int x = a[i];
        for (int j = 2; j * j <= x; j++){
            if (x % j == 0){
                while (x % j == 0)
                    x /= j;
                g[i].push_back({j + n, 1});
                g[j + n].push_back({i, 0});
            }
        }
        if (x != 1){
            g[i].push_back({x + n, 1});
            g[x + n].push_back({i, 0});
        }
	}
    cin>>s>>t;
    if(s == t){
    	cout<<1<<endl<<s;
    	return 0;
	}
	dijk(s);
	Maxx = dis[0];
    if(dis[t] != Maxx){
    	dfs2(t);
	    cout<<ans<<endl;
        dfs(t);
    }
    else cout<<-1; 
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值