UOJ550 【UNR #4】网络恢复【交互,随机权值】

这是一道交互题

交互器有 \(n\) 个点 \(m\) 条边的无向简单图,你只知道 \(n,m\)。每次询问,你可以给每个点定 ULL 权值,给每条边(按编号)定黑白颜色,交互器对于每个节点 \(i\) 计算与它通过黑边相邻的所有点的点权异或和。你需要询问至多 \(50\) 次来求出边集,但你并不需要确定每条边的编号。

\(n\le 5\times 10^4\)\(m\le 3\times 10^5\),图随机生成。


这个图看上去比较稀疏,可以赋随机权值,叶子的返回值就是它连向的点的权值,可以直接把所有叶子剥掉。

最后剩下的图中度数 \(\ge 2\),我们假装有一个点的度数 \(=2\),枚举它的其中一条边就可以把另一条边求出来,同样可以继续剥叶子。

为了这个过程不要太慢,可以把边均分成 \(50\) 块,每块分别做。

#include<bits/stdc++.h>
#include"explore.h"
#define PB emplace_back
using namespace std;
typedef unsigned long long ULL;
namespace {
const int N = 300003;
mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count());
int n, m, blk, q[N], fr, re;
vector<ULL> A, B;
unordered_map<ULL, int> mp;
void rep(int x, int y){
	Report(x+1, y+1);
	B[x] ^= A[y]; B[y] ^= A[x];
	if(B[x] && mp.count(B[x])) q[re++] = x;
	if(B[y] && mp.count(B[y])) q[re++] = y;
}}
void Solve(int _1, int _2){
	n = _1; m = _2; A.resize(n);
	for(int i = 0;i < n;++ i) mp[A[i] = rng()] = i;
	blk = (m + 49) / 50;
	for(int k = 0;k < 50;++ k){
		vector<int> E;
		for(int i = k*blk;i < (k+1)*blk && i < m;++ i) E.PB(i+1);
		B = Query(A, E);
		for(int i = 0;i < n;++ i)
			if(B[i] && mp.count(B[i])) q[re++] = i;
		while(true){
			while(fr < re){
				int u = q[fr++]; if(B[u]) rep(u, mp[B[u]]);
			} fr = re = 0; vector<int> C;
			for(int i = 0;i < n;++ i) if(B[i]) C.PB(i);
			if(C.empty()) break;
			while(true){
				int x = rng() % C.size(), y = rng() % C.size();
				if(x == y) continue; x = C[x]; y = C[y];
				if(mp.count(B[x]^A[y]) || mp.count(B[y]^A[x])){rep(x, y); break;}
			}
		}
	}
}
posted @ 2021-07-09 19:26  mizu164  阅读(105)  评论(0编辑  收藏  举报