【BZOJ3251】树上三角形 暴力

【BZOJ3251】树上三角形

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

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

HINT

对于100%的数据,n,q<=100000,点权范围[1,231-1]

题解:正常人看到题,大概都会想到什么树剖+树套树套树什么的吧~

一种naive的做法就是,先将路径上的所有数都拿出来排序,每次只需要判断相邻的三个数能否形成三角形就行了。

仔细观察发现,如果答案为N,那么最坏的情况,就是在排完序后,任意相邻的三个数都满足x<y<z且x+y=z。这不就是斐波那契数列吗?

有什么用呢?

斐波那契数列的增长不是指数级的吗?

也就意味着一旦路径的长度>logn(实测f(47)>2147483647,所以取47或50即可),我们的结果就是Y。

难道我们还要用倍增求出路径长度吗?

朴素LCA就行辣!一旦跑了50次,就直接输出Y。否则就将所有数拿出来,用naive的做法搞一下就行了。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=100010;
int n,m,sum,cnt;
int to[maxn<<1],next[maxn<<1],head[maxn];
int fa[maxn],dep[maxn],v[maxn],p[60];
int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
void dfs(int x)
{
	for(int i=head[x];i!=-1;i=next[i])	fa[to[i]]=x,dep[to[i]]=dep[x]+1,dfs(to[i]);
}
void add(int a,int b)
{
	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
int main()
{
	n=rd(),m=rd();
	int i,j,a,b,c;
	for(i=1;i<=n;i++)	v[i]=rd();
	memset(head,-1,sizeof(head));
	for(i=1;i<n;i++)	a=rd(),b=rd(),add(a,b);
	dep[1]=1,dfs(1);
	for(i=1;i<=m;i++)
	{
		c=rd(),a=rd(),b=rd(),sum=0;
		if(c)
		{
			v[a]=b;
			continue;
		}
		if(dep[a]<dep[b])	swap(a,b);
		while(dep[a]>dep[b]&&sum<50)	p[++sum]=v[a],a=fa[a];
		while(a!=b&&sum<50)	p[++sum]=v[a],p[++sum]=v[b],a=fa[a],b=fa[b];
		p[++sum]=v[a];
		if(sum>=50)
		{
			printf("Y\n");
			continue;
		}
		sort(p+1,p+sum+1);
		for(j=3;j<=sum;j++)
		{
			if(p[j]-p[j-1]<p[j-2])
			{
				printf("Y\n");
				break;
			}
		}
		if(j>sum)	printf("N\n");
	}
	return 0;
}
时间: 2024-10-13 21:25:09

【BZOJ3251】树上三角形 暴力的相关文章

BZOJ 3251 树上三角形 暴力

题目大意:给定一棵树,每个点上有点权,多次修改点权,以及查询两点间路径上所有点权之间能否找出三个值构成三角形的三边长 被逗了- - 首先考虑如果一些数不能构成三角形的三边长,那么这些数最多有多少个? 显然当这些数构成斐波那契数列的时候数值的个数最多- - 那么2^31以内共有多少个斐波那契数?46! 也就是说当两点间路径上的点>=47时答案一定是YES! 那么小于47时只要暴力就行- - 时间复杂度O(mlogk) 其中k是最大的数的大小- - #include <cstdio> #in

bzoj3251: 树上三角形(思维题)

神tmWA了8发调了20min才发现输出没回车T T... 首先考虑一段什么样的序列才会是N... 显然最长的形式就是斐波那契,前两数之和等于第三数之和,这样就无法组成三角形并且序列最长.可以发现在int范围内斐波那契数列不会超过50个,所以如果这段路径上节点数超过50个直接输出Y,否则把50个数拉出来排序暴力找是否有三角形就好了. #include<iostream> #include<cstring> #include<cstdlib> #include<cs

BZOJ3251 树上三角形

一看这题...难道要链剖乱搞什么的吗...不会啊汗... 突然发现不构成三角形的条件其实非常苛刻,由斐波那契数列: 1,1,2,3,5,8,13,21,34...... 可以知道其实小于int的大概就50项的样子. 于是路径长度>50直接输出'Y',否则排序判断... 看来还是蛮快的... 1 /************************************************************** 2 Problem: 3251 3 User: rausen 4 Langu

树上三角形(斐波那契数列神奇应用)

树上三角形(斐波那契数列神奇应用) Description给定一个大小为 n 的有点权树,需要支持两个操作.0:询问(u,v),能否在 u 到 v 的简单路径上取三个点,使这三个点的点权作为边长可以构成一个三角形.1:修改某个点的点权. Input第一行两个整数 n,q 表示树的点数和操作数.第二行 n 个整数表示 n 个点的初始的点权.接下来 n-1 行,每行两个整数 a,b,表示 a 是 b 的父亲.接下来 q 行,每行三个整数 op,a,b:若 op=0,则表示询问(a,b).若 op=1

【bzoj3251】树上三角形 朴素LCA+暴力

题目描述 给定一大小为n的有点权树,每次询问一对点(u,v),问是否能在u到v的简单路径上取三个点权,以这三个权值为边长构成一个三角形.同时还支持单点修改. 输入 第一行两个整数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 输出 对每个询问输出一行表示答案,“Y”表示有解,“N”表示无解. 样例输入 5 5 1 2

树上三角形

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 对每个

BZOJ 3251 树上三角形

NOIP的东西回成都再说吧... 这题暴力. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxv 100500 #define maxe 200500 using namespace std; int n,q,x,y,z,val[maxv],anc[maxv][20],dis[maxv],g[maxv],nume=0; int s[max

1079 三角形

1079 三角形 时间限制:500MS  内存限制:65536K提交次数:283 通过次数:82 题型: 编程题   语言: G++;GCC Description 著名的数学家毕达哥拉斯可能从来都不曾想过有人居然会问他这样的一个问题:给出一个整数,存在多少个直角三角形, 它的某一条边的长度等于这个整数,而且其他边的长度也是整数.既然毕达哥拉斯不可能预见到有计算机的出现, 如果他回答不出来,那谁又能责怪他呢?但是现在既然你有了计算机,那么回答不出来就说不过去了. 输入格式 第一行有一个整数n,代

hdu 1247 Hat’s Words 字典树

// hdu 1247 Hat's Words 字典树 // // 题目大意: // // 在一些字符串中,找到这样字符串:由两个其他的字符串构成 // // 解题思路: // // 字典树,先将这些字符串插入到字典树中,然后枚举断点,如果 // 字符串的前后两段都找到了,输出该串即可~ // // 感悟: // // 这道题目的话,就是字典树上的暴力嘛,细节方面还是要多多注意 // val值还是不能少哟~因为查找到了该串,不一定是一个单词,可能 // 是中间的一个节点,即某个字符串的前缀~~~