BZOJ 3251: 树上三角形 - Gemini Boy - ACM之路~

BZOJ 3251: 树上三角形

Gemini posted @ 2013年8月16日 04:30 in 题解 with tags 数据结构 bzoj , 1092 阅读

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3251

题意就是给一棵树,点权,然后查询一条链上是否有3个点的点权能组成一个三角形。

注意到三角形任意2边之和大于第三边,然后最坏的情况类似于斐波那契数列,大约4 50左右的时候,就会超int。所以当链的长度大于45的时候,返回true,否则就暴力判断是否可行。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

const int maxn = 101110;

int N, Q;
vector<int> next[maxn];
long long val[maxn];
int par[maxn], dep[maxn];

void dfs(int u) {
	for (int i = 0; i < next[u].size(); i++) {
		int v = next[u][i];
		//if (dep[v]) continue;
		dep[v] = dep[u] + 1;
		dfs(v);
	}
}

bool check(int x, int y) {
	int cnt = 0;
	long long num[55];
	for ( ; dep[x] > dep[y]; x = par[x]) {
		num[cnt++] = val[x];
		if (cnt > 45) return true;
	}
	for ( ; x != y; x = par[x], y = par[y]) {
		num[cnt++] = val[x];
		num[cnt++] = val[y];
		if (cnt > 45) return true;
	}
	num[cnt++] = val[y];
	if (cnt < 3) 
		return false;
	sort(num, num + cnt);
	for (int i = 0; i + 2 < cnt; i++) {
		if (num[i] + num[i+1] > num[i+2])
			return true;
	}
	return false;
}

void init() {
	for (int i = 0; i < maxn; i++) {
		next[i].clear();
		dep[i] = 0;
		val[i] = 0;
		par[i] = 0;
	}
	par[1] = -1;
	scanf("%d %d", &N, &Q);
	for (int i = 1; i <= N; i++)
		scanf("%d", &val[i]);
	for (int i = 1; i < N; i++) {
		int x, y;
		scanf("%d %d", &x, &y);
		par[y] = x;
		next[x].push_back(y);
	}
	dep[1] = 1;
	dfs(1);
}

void work() {
	for (int i = 0; i < Q; i++) {
		int opt, x, y;
		scanf("%d %d %d", &opt, &x, &y);
		if (opt == 1)
			val[x] = y;
		else {
			if (dep[x] < dep[y])
				swap(x, y);
			if (x == y || x == par[y] || y == par[x]) {
				puts("N");
				continue;
			}
			if (check(x, y) == true)
				puts("Y");
			else puts("N");
		}
	}
}

int main() {
	init();
	work();
	return 0;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter
Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee