J. Not Another Path Query Problem

J. Not Another Path Query Problem_第1张图片

 很有帮助的拆位题

判断u、v之间有无“所有边权相与”>=V的路径

1 & 1 = 1, 1 & 0 = 0, 0 & 1 = 0, 0 & 0 = 0

一条路径上所有边权的与值A大于等于V有两种情况:

①A > V  V的第i位为0时,A的这一位为1,前面与V相同,后面都为0(后面的每一位值其实都可以任意,但如果1多的话后面删边会删的很多,漏掉不少情况,1的数量保持最少可以囊括更多情况,做到不重不漏)

②A = V  

然后保留某些边,余下的这些边s, 满足s & A = A,也就是A中为1的s也为1,这样的边才能保留下来

我们用并查集判断联通,复杂度为O(m * 62)

#include
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'
 
using namespace std;
 
typedef pair PII;
typedef long long ll;
typedef long double ld;

const int N = 100010, M = 500010;

struct Node
{
	int a, b;
	ll w;
}edges[M];
int p[N];
int n, m, Q;
ll V;
bool ans[M];
PII que[M];

int find(int x)
{
	if(p[x] == x)return x;
	return p[x] = find(p[x]);
}

int main()
{
	IOS
	cin >> n >> m >> Q >> V;
	
	for(int i = 1; i <= m; i ++)
	{
		int a, b;
		ll w;
		cin >> a >> b >> w;
		edges[i] = {a, b, w};
	}
	for(int i = 1; i <= Q; i ++)
	{
		int a, b;
		cin >> a >> b;
		que[i] = {a, b};
	}
	
	for(int i = 60; i >= 0; i --)
	{
		if(V >> i & 1)continue;
		
		for(int i = 1; i <= n; i ++)p[i] = i;
		ll res = ((V >> i) + 1) << i;
		for(int j = 1; j <= m; j ++)
		{
			int a = edges[j].a, b = edges[j].b;
			ll w = edges[j].w;
			if((w & res) != res)continue;
			
			int pa = find(a), pb = find(b);
			if(pa != pb)
			{
				p[pa] = pb;
			}
		}
		
		for(int j = 1; j <= Q; j ++)
		{
			int pa = find(que[j].first), pb = find(que[j].second);
			if(pa == pb)ans[j] = true;
		}
	}
	
	for(int i = 1; i <= n; i ++)p[i] = i;
	ll res = V;
	for(int j = 1; j <= m; j ++)
	{
		int a = edges[j].a, b = edges[j].b;
		ll w = edges[j].w;
		if((w & res) != res)continue;
		
		int pa = find(a), pb = find(b);
		if(pa != pb)
		{
			p[pa] = pb;
		}
	}
	
	for(int j = 1; j <= Q; j ++)
	{
		int pa = find(que[j].first), pb = find(que[j].second);
		if(pa == pb)ans[j] = true;
	}
	
	for(int i = 1; i <= Q; i ++)
	{
		if(ans[i])cout << "Yes" << endl;
		else cout << "No" << endl;
	}
	
	
	return 0;
}

你可能感兴趣的:(日常水题,c++,算法)