zoukankan      html  css  js  c++  java
  • 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
    ",len[i]);
    	}*/
    	while(q--) {
    		int opt=read();
    		if(opt) {
    			x=read(),y=read();
    			pv[x]=y;
    		}
    		else {
    			x=read(),y=read();
    			query(x,y);
    		}
    	}
    }
    

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

  • 相关阅读:
    NET C#测试程序运行时间
    openGL 高程配色绘制点云(csGL)
    openGL 绘制文本font(csGL)
    openGL 选择和反馈(csGL)
    简单实现angular2组件双向绑定
    angular2 ChangeDetectorRef (变化检测器的引用)手动控制组件的变化检测行为
    Angular 2 Forward Reference (可用作获取父组件对象)
    两个iframe之间tab切换,谷歌浏览器的滚动条会消失
    js随机从数组中取出几个元素
    原生js javascript 实现trigger(自动触发window 的resize事件)
  • 原文地址:https://www.cnblogs.com/Tobichi/p/9079129.html
Copyright © 2011-2022 走看看