BZOJ 3251: 树上三角形

3251: 树上三角形

Description

给定一大小为n的有点权树,每次询问一对点(u,v),问是否能在u到v的简单路径上取三个点权,以这三个权值为边
长构成一个三角形。同时还支持单点修改。

Input

第一行两个整数n、q表示树的点数和操作数
第二行n个整数表示n个点的点权
以下n-1行,每行2个整数a、b,表示a是b的父亲(以1为根的情况下)
以下q行,每行3个整数t、a、b
若t=0,则询问(a,b)
若t=1,则将点a的点权修改为b
n,q<=100000,点权范围[1,2^31-1]
 

Output

对每个询问输出一行表示答案,“Y”表示有解,“N”表示无解。

Sample Input

5 5
1 2 3 4 5
1 2
2 3
3 4
1 5
0 1 3
0 4 5
1 1 4
0 2 5
0 2 3

Sample Output

N
Y
Y
N

思路:

  脑洞题,考虑到MAXINT范围内完全不能构成三角形的数字有多少---Fib数列,在47项的时候爆INT,所以只要路径上有超过47个点直接输出Y,没有超过47个点可以暴力把所有点压入数组,并排序枚举相邻三个点能否构成三角形,注意存在两点相加爆INT的情况,枚举之后不满足则输出N,因为每次暴力不超过50,所以复杂度相当低。我考场上还写了一个树剖,汗。类似找LCA的过程,一层一层爬就好,记得在循环里判当前是否到47个了!

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cctype>
#include <iostream>
using namespace std;
const int N = 120000;
int fa[N],dep[N],pv[N];
int q[60];
inline char nc() {
	static char buf[100000], *p1, *p2;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin)),p1==p2?EOF:*p1++;
}
inline int read() {
	int x=0;char ch=nc();
	while(!isdigit(ch))ch=nc();
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=nc();}
	return x;
}
int cnt,head[N<<2],to[N<<2],next[N<<2];
inline void add_edge(int a,int b) {
	to[++cnt]=b;
	next[cnt]=head[a];
	head[a]=cnt;
	to[++cnt]=a;
	next[cnt]=head[b];
	head[b]=cnt;
}
void dfs1(int p) {
	dep[p]=dep[fa[p]]+1;
	int i;
	for(i=head[p];i;i=next[i]) {
		if(to[i]!=fa[p]) {
			fa[to[i]]=p;
			dfs1(to[i]);
		}
	}
}
void query(int a,int b) {
	int cnt1=0;
	if(dep[b]>dep[a])
		swap(a,b);
	while(dep[a]>dep[b]) {
		q[++cnt1]=pv[a];
		a=fa[a];
		if(cnt1>46) {
			puts("Y");
			return;
		}
	}
	while(a!=b) {
		q[++cnt1]=pv[a];
		q[++cnt1]=pv[b];
		a=fa[a],b=fa[b];
		if(cnt1>46) {
			puts("Y");
			return;
		}
	}
	q[++cnt1]=pv[a];
	if(cnt1>46) {
		puts("Y");
		return;
	}
	sort(q+1,q+cnt1+1);
	int i;
	for(i=3;i<=cnt1;i++) {
		if(q[i]-q[i-2]<q[i-1]) {
			puts("Y");
			return;
		}
	}
	puts("N");
}
int main() {
	int n,q;
	n=read(),q=read();
	int i;
	for(i=1;i<=n;i++)
		pv[i]=read();
	int x,y;
	for(i=1;i<n;i++) {
		x=read(),y=read();
		add_edge(x,y);
	}
	dfs1(1);
	//dfs2(1,1,1);
	/*for(i=1;i<=n;i++) {
		printf("%d\n",len[i]);
	}*/
	while(q--) {
		int opt=read();
		if(opt) {
			x=read(),y=read();
			pv[x]=y;
		}
		else {
			x=read(),y=read();
			query(x,y);
		}
	}
}

 欢迎到原博客看看 >原文链接<

posted @ 2018-05-23 20:20  TOBICHI_ORIGAMI  阅读(127)  评论(1编辑  收藏  举报