AcWing4202円を通過します(ツリー上の最短経路/ビットセット最適化ブルートフォース)

トピックリンク:サークルを通じて

一般的なアイデア

与えられたnnポイント、mmm個の円。各点が円の端にないこと、および円と円が交差しないことが保証されています。

kkを持っているk回のクエリで、各クエリは2つのポイントa、ba、bを_b、少なくともいくつの円を通過する必要があるか。

問題解決のアイデア

アイデア1:ツリー上の最短経路問題に変換する

タイトルは円と円が交差せず、点が円上にないことを保証しているためと考えます。次に、完全なセットをm + 1 m+1に設定するとm+1円、次にnnnポイントはすべてm+1 m+1m+1サークル。

ある点を考えればpppが属する円のとおりです。点ppを含むp、および最小半径。次に、各点には、それが属する円ます。

毎回a、ba、bの2点を尋ねることを検討します_b:
​ ①若 a , b a, b _bは同じ円の中にあり、答えは000.
​ ②若 a , b a, b _bが同じ円にない場合は、点a、ba、b_bは線を開始し、点aaのみを通過しますaまたはドットbba、ba、bの両方を含む最初のエッジに遭遇するまでのbの丸みを帯びたエッジ_bの円が2本の線で結ばれている場合、

②は、ツリー内の最も近い共通祖先の概念に非常に類似していることがわかります。問題がツリーに抽象化されている場合、エッジの重みを11にするのと同じです1のツリー上の任意の2点の最短経路ツリー上の差


アイデア2:暴力を最適化する

アイデア1の分析を通じて、次の結論を導き出すことができます。ポイントa、ba、bを接続する場合_b 穿过最少圆的数量 = 仅包含点a的圆数量 + 仅包含点b的圆数量

しかし、1 0 5 10^5があることを考えると1 05件のお問い合わせ、1 0 3 10 ^ 31 03つの円、時間計算量は1 0 8 10^81 08、0.3秒で難しい0.3秒0.3秒の制限時間内に通過しました

問題の本質を観察しますaはbbませんbbbb不在 a a セット。これは基本的にセットのXORビットセットを渡すことができます。b i t set最適化れた実装。

➡️ビットセット最適化セットの問題がわからない場合は、最初にこの問題を実行できます⬅️

ACコード

ツリー内の最短経路に変換する

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E3 + 10;
pair<int, int> p[N];
struct node {
    
     int x, y, r; } cir[N];
int in[N];

bool fact(const pair<int, int> a, const node& b) {
    
    
	int x1 = a.first, y1 = a.second;
	int x2 = b.x, y2 = b.y; int r = b.r;
	int x = x1 - x2, y = y1 - y2;
	return 1ll * x * x + 1ll * y * y <= 1ll * r * r;
}

vector<int> edge[N];
/* 倍增求LCA模版 */
namespace LCA {
    
    
	const int B = 10; // 记录真实的B, f数组多开1即可
	int dep[N], f[N][B + 1];
	void dfs(int x = 1, int fa = 0) {
    
    
		dep[x] = dep[fa] + 1;
		f[x][0] = fa;
		rep(i, B) f[x][i] = f[f[x][i - 1]][i - 1];
		for (auto& to : edge[x]) if (to != fa) dfs(to, x);
	}
	int lca(int x, int y) {
    
    
		if (dep[x] < dep[y]) swap(x, y);
		for (int i = B; i >= 0; --i) if (dep[f[x][i]] >= dep[y]) x = f[x][i];
		if (x == y) return x;
		for (int i = B; i >= 0; --i) if (f[x][i] != f[y][i]) x = f[x][i], y = f[y][i];
		return f[x][0];
	}
}
int main()
{
    
    
	int n, m, k; cin >> n >> m >> k;
	rep(i, n) {
    
    
		int x, y; scanf("%d %d", &x, &y);
		p[i] = {
    
     x, y };
	}
	rep(i, m) {
    
    
		int r, x, y; scanf("%d %d %d", &r, &x, &y);
		cir[i] = {
    
     x, y, r };
	}

	rep(i, n) {
    
    
		rep(j, m) {
    
    
			if (fact(p[i], cir[j])) {
    
    
				if (!in[i] or cir[in[i]].r > cir[j].r) in[i] = j;
			}
		}
		if (!in[i]) in[i] = m + 1;
	}

	rep(i, m) {
    
    
		int index = 0;
		rep(j, m) {
    
    
			if (cir[j].r > cir[i].r and fact({
    
     cir[i].x, cir[i].y }, cir[j])) {
    
    
				if (!index or cir[index].r > cir[j].r) index = j;
			}
		}
		if (!index) index = m + 1;
		edge[index].push_back(i), edge[i].push_back(index);
	}

	LCA::dfs();

	rep(i, k) {
    
    
		int a, b; scanf("%d %d", &a, &b);
		a = in[a], b = in[b];
		int lca = LCA::lca(a, b);
		int res = LCA::dep[a] + LCA::dep[b] - 2 * LCA::dep[lca];
		printf("%d\n", res);
	}

	return 0;
}

ビットセットは暴力を最適化します

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E3 + 10;
pair<int, int> p[N];
bitset<N> bt[N];
struct node {
    
     int x, y, r; }cir[N];

bool fact(const pair<int, int>& a, const node& b) {
    
    
	int x1 = a.first, y1 = a.second;
	int x2 = b.x, y2 = b.y;
	int x = x1 - x2, y = y1 - y2;
	return sqrt(1ll * x * x + 1ll * y * y) < b.r;
}
int main()
{
    
    
	int n, m, k; cin >> n >> m >> k;
	rep(i, n) {
    
    
		int x, y; scanf("%d %d", &x, &y);
		p[i] = {
    
     x, y };
	}
	rep(i, m) {
    
    
		int r, x, y; scanf("%d %d %d", &r, &x, &y);
		cir[i] = {
    
     x, y, r };
	}

	rep(i, n) rep(j, m) {
    
    
        bt[i][j] = fact(p[i], cir[j]);
    }

	rep(i, k) {
    
    
		int a, b; scanf("%d %d", &a, &b);
		printf("%d\n", (bt[a] ^ bt[b]).count());
	}

    return 0;
}

終わり

おすすめ

転載: blog.csdn.net/weixin_45799835/article/details/122252217