BZOJ3251 树上三角形
以传统的维护思路特别不可做。完全想不到的一点是,如果构造一个int内的数列使其中任意三个数都不能构成三角形,项数最多的方案显然是斐波拉契数列,而斐波拉契数列的项数显然是log级的。那么我们求出询问点之间的距离,如果超过项数直接输出,否则暴力判断即可。
开始算距离的时候没把lca*2调了半天,而且明明可以暴力的为什么还写倍增啊。大概脑子坏了。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define N 100010 #define int unsigned int int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } int n,m,a[N],p[N],fa[N][18],deep[N],q[61],t=0; struct data{int to,nxt; }edge[N]; void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;} void dfs(int k) { for (int i=p[k];i;i=edge[i].nxt) if (edge[i].to!=fa[k][0]) { deep[edge[i].to]=deep[k]+1; dfs(edge[i].to); } } int lca(int x,int y) { if (deep[x]<deep[y]) swap(x,y); for (int j=17;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j]; if (x==y) return x; for (int j=17;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j]; return fa[x][0]; } signed main() { #ifndef ONLINE_JUDGE freopen("bzoj3251.in","r",stdin); freopen("bzoj3251.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<n;i++) { int x=read(),y=read(); addedge(x,y);fa[y][0]=x; } fa[1][0]=1; for (int j=1;j<18;j++) for (int i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; dfs(1); while (m--) { int op=read(),x=read(),y=read(); if (op==0) { int l=lca(x,y); if (deep[x]+deep[y]-(deep[l]<<1)>60) printf("Y\n"); else { int cnt=0; while (x!=l) q[++cnt]=a[x],x=fa[x][0]; while (y!=l) q[++cnt]=a[y],y=fa[y][0]; q[++cnt]=a[l]; sort(q+1,q+cnt+1); bool flag=1; for (int i=1;i<=cnt-2;i++) if (q[i]+q[i+1]>q[i+2]) {flag=0;break;} if (flag) printf("N\n"); else printf("Y\n"); } } else a[x]=y; } return 0; }