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
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
Y
Y
N
HINT
对于100%的数据,n,q<=100000,点权范围[1,2^31-1]
题解
感觉非常奇怪,一道结论题。
要求简单路径还有路径上每个点的权值,所以不能用倍增,只可以一个一个搞。对于所有权值,排序以下就可以最坏O(n)的情况下算出是否可构成三角形。这样做有30分。
正解需要一个结论,因为点权在int范围(c++),所以都没有三角型的情况最多为1,1,2,3,5……即斐波那契数列,然而在int范围内大约有40多50个数。所以只要点数大约大于45即可认为有三角形。在暴力中找权值是加上该判断即可。
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<cmath> #include<algorithm> #define MAXN 100002 #define ll long long using namespace std; int n,m,zz,head[MAXN]; struct bian{int to,nx;} e[MAXN*2]; int h[MAXN],fa[MAXN];//2^17>10^5 ll a[MAXN],v[MAXN]; int top; void insert(int x,int y) { zz++; e[zz].to=y; e[zz].nx=head[x]; head[x]=zz; zz++; e[zz].to=x; e[zz].nx=head[y]; head[y]=zz; } void init() { scanf("%d%d",&n,&m); int i,x,y; for(i=1;i<=n;i++) scanf("%lld",&v[i]); for(i=1;i<n;i++) {scanf("%d%d",&x,&y); insert(x,y); } } //------------------------------------------------------------ void dfs(int x) { int i,p; for(i=head[x];i;i=e[i].nx) {p=e[i].to; if(p==fa[x]) continue; fa[p]=x; h[p]=h[x]+1; dfs(p); } } bool geta(int x,int y) { if(h[x]<h[y]) swap(x,y); top=0; for(;h[x]>h[y];x=fa[x]) {a[++top]=v[x]; if(top>45) return true; } while(x!=y) {a[++top]=v[x]; x=fa[x]; a[++top]=v[y]; y=fa[y]; if(top>45) return true; } a[++top]=v[x]; if(top>45) return true; sort(a+1,a+top+1); for(int i=1;i<top-1;i++) {if(a[i]+a[i+1]>a[i+2]) return true;} return false; } void work() { int i,x,y,t; for(i=1;i<=m;i++) {scanf("%d%d%d",&t,&x,&y); if(t==0) {if(x==y||x==fa[y]||y==fa[x]) {printf("N\n"); continue;} if(geta(x,y)) printf("Y\n"); else printf("N\n"); } else v[x]=y; } } int main() { freopen("sdtg.in","r",stdin); freopen("sdtg.out","w",stdout); init(); dfs(1); work(); return 0; }