給定一大小爲n的有點權樹,每次詢問一對點(u,v),問是否能在u到v的簡單路徑上取三個點權,以這三個權值爲邊
長構成一個三角形。同時還支持單點修改。
對每一個詢問輸出一行表示答案,「Y」表示有解,「N」表示無解。ios
N
Y
Y
Ngit
腦洞題,考慮到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); } } }
歡迎到原博客看看 >原文連接<spa