點分治和動態點分治( 在更)

點分治

例題

ciel the commander

來源:codeforces 321 C

題解:

讓你給一個樹每個點用小寫字母標號, 要求每兩個相同的標號之間的路徑上至少有一個標號比他們大的點。

甚至算不上點分治,但是可以練習一下點分的求重心。

考慮貪心,每次找一個點標當前最高的號,然後一棵樹分成了幾棵子樹,子樹之間的路徑肯定會經過當前標號的點,就不需要考慮了,那麼遞歸下去就好了。

然後假如每次對於一棵子樹選他的重心標號,最多只需要O(log  n)O(log \; n)個標號就好了。

Tree

來源:poj 1741

題解:

一棵樹,求有多少組點對,距離不超過k。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
void chkMax(int &x, int y){if (x < y) x = y;}
void chkMin(int &x, int y){if (x > y) x = y;}
const int N = 1e4+10;
const int M = N<<1;
const int inf = 1e9+7;
struct G{
	int h[N], e, nxt[M], v[M], w[M];
	void clear(){
		memset(h, 0, sizeof(h));
		e = 1;
	}
	void add_dir(int _u, int _v, int _w){
		++ e;
		nxt[e] = h[_u];
		v[e] = _v;
		w[e] = _w;
		h[_u] = e;
	}
	void add_undir(int _u, int _v, int _w){
		add_dir(_u, _v, _w);
		add_dir(_v, _u, _w);
	}
}g;
int n, k, ans;
int sz[N], zx, mx, siz;
int l, r, q[N], dpt[N];
bool vis[N];

void dfs2(int u, int fa)
{
	q[++ r] = dpt[u];
	for (int i = g.h[u]; i; i = g.nxt[i]){
		int v = g.v[i];
		int w = g.w[i];
		if (v == fa || vis[v]) continue;
		dpt[v] = dpt[u]+w;
		dfs2(v, u);
	}
}

int calc(int u, int val)
{
	int ret = 0;
	l = 1; r = 0; dpt[u] = val;
	dfs2(u, 0);
	sort(q+1, q+r+1);
	while (l < r){
		if (q[l]+q[r] <= k) ret += r-l, ++ l;
		else -- r;
	}
	return ret;
}

void get_zx(int u, int fa)
{
	sz[u] = 1;
	int tmp = 0;
	for (int i = g.h[u]; i; i = g.nxt[i]){
		int v = g.v[i];
		if (v == fa || vis[v]) continue;
		get_zx(v, u);
		chkMax(tmp, sz[v]);
		sz[u] += sz[v];
	}
	chkMax(tmp, siz-sz[u]);
	if (tmp < mx) mx = tmp, zx = u;
}

void dfs1(int u)
{
	vis[u] = 1;
	ans += calc(u, 0);
	for (int i = g.h[u]; i; i = g.nxt[i]){
		int v = g.v[i];
		int w = g.w[i];
		if (vis[v]) continue;
		siz = sz[v]; mx = inf;
		ans -= calc(v, w);
		get_zx(v, u);
		dfs1(zx);
	}
}

int main()
{
	while(scanf("%d%d", &n, &k) && n && k){
		g.clear();
		ans = 0;
		for (int i = 1; i < n; ++ i){
			int x, y, z;
			scanf("%d%d%d", &x, &y, &z);
			g.add_undir(x, y, z);
		}
		memset(vis, 0, sizeof(vis));
		siz = n; mx = inf;
		get_zx(1, 0);
		dfs1(zx);
		printf("%d\n", ans);
	}
	return 0;
}

最短路徑樹問題

來源:bzoj4016

重建計劃

來源:bzoj1758[WC2010]

動態點分治

例題

[ZJOI2007]捉迷藏

板子題。

題解鏈接在這裏:my solution

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章