problem
Description
给定一个n个点的以1为根的树,每个点有一个正整数点权。
有q个操作,每个操作为以下类型之一:
1. 1 u v 询问树上所有在u到v的简单路径的节点(含u,v)中,是否存在三个不同的节点,使得以这三个节点的点权为边长的三条边能够构成一个三角形。
2. 2 u v 将节点u的权值改成v。
3. 3 u v 若节点v不在以节点u为根的子树里,那么令u的父节点为v,否则令v的父节点为u,如果u=v那么忽略这一条操作。
所有操作按输入的顺序进行。
这个题面应该不会看不懂吧。。
Input
第一行有两个正整数n,q,表示树的节点数和操作数。
第二行n个正整数,表示每个节点的点权。
第三行有n-1个正整数,第i个数表示节点i+1的父节点编号,保证所给定的是一棵树。
接下来q行,每行三个正整数t u v,意义如问题描述中所示。
Output
对每个询问输出一行表示答案,“Y”表示有解,“N”表示无解。
Sample Input
5 5
1 2 3 4 5
1 2 3 1
1 1 3
1 4 5
2 1 4
1 2 5
1 2 3
Sample Output
N
Y
Y
N
Data Constraint
对于20%的数据,保证n,q<=1000
对于另外30%的数据,保证对于每个操作,t<=2
对于再另外的30%的数据,保证询问操作不超过20次。
对于100%的数据,保证n<=100000 q<=200000 每个节点的权值<=(2^31)-1
analysis
80% 80 % 以下的数据都是模拟什么的
正解暴力LCT……
思考把 x,y x , y 之间的节点权值拉出来升序排序,共有 k k 个点
能够成三角形就满足那么最长不满足这样的东西就是斐波那契数列
而节点权值都在 int i n t 范围内,所以 x,y x , y 之间节点数超过 50 50 个就一定合法
维护查询什么的直接上LCT
判断 x,y x , y 的话,就 makeroot(y),access(x) m a k e r o o t ( y ) , a c c e s s ( x ) ,再用 getroot g e t r o o t 判断
查询 x,y x , y 的话,就 makeroot(y),access(x),splay(x,0) m a k e r o o t ( y ) , a c c e s s ( x ) , s p l a y ( x , 0 ) ,再bfs遍历整棵splay就好
code
#include<bits/stdc++.h>
#define MAXN 100001
using namespace std;
int t[MAXN][2];
int b[MAXN],fat[MAXN],fa[MAXN],pf[MAXN],st[MAXN];
int n,q,tot;
struct node
{
long long val;
int size,rev;
}a[MAXN];
bool cmp(int x,int y)
{
return a[x].val<a[y].val;
}
int read()
{
int x=0,f=1;
char ch=getchar();
while (ch<'0' || '9'<ch)
{
if (ch=='-')f=-1;
ch=getchar();
}
while ('0'<=ch && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
long long readll()
{
long long x=0,f=1;
char ch=getchar();
while (ch<'0' || '9'<ch)
{
if (ch=='-')f=-1;
ch=getchar();
}
while ('0'<=ch && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void reverse(int x)
{
if(x)
{
a[x].rev^=1;
swap(t[x][0],t[x][1]);
}
}
void down(int x)
{
if (a[x].rev)
{
reverse(t[x][0]),reverse(t[x][1]);
a[x].rev=0;
}
}
void update(int x)
{
if (x)
{
a[x].size=a[t[x][0]].size+a[t[x][1]].size+1;
}
}
void downdata(int x)
{
st[0]=0;
while (x)st[++st[0]]=x,x=fa[x];
while (st[0])down(st[st[0]--]);
}
int lr(int x)
{
return t[fa[x]][1]==x;
}
void rotate(int x)
{
int y=fa[x],k=lr(x);
t[y][k]=t[x][!k];
if (t[x][!k])fa[t[x][!k]]=y;
fa[x]=fa[y];
if (fa[y])t[fa[y]][lr(y)]=x;
t[x][!k]=y;
fa[y]=x,pf[x]=pf[y];
update(y),update(x);
}
void splay(int x, int y)
{
downdata(x);
while (fa[x]!=y)
{
if (fa[fa[x]]!=y)
{
if (lr(x)==lr(fa[x]))rotate(fa[x]);
else rotate(x);
}
rotate(x);
}
}
void access(int x)
{
for (int y=0;x;update(x),y=x,x=pf[x])
{
splay(x,0);
fa[t[x][1]]=0;
pf[t[x][1]]=x;
t[x][1]=y;
fa[y]=x;
pf[y]=0;
}
}
void makeroot(int x)
{
access(x);
splay(x,0);
reverse(x);
}
int getroot(int x)
{
while (fa[x])x=fa[x];
return x;
}
bool judge(int x,int y)
{
makeroot(x);
access(y);
splay(x,0);
return getroot(y)==x;
}
void link(int x,int y)
{
makeroot(x);
pf[x]=y;
}
void cut(int x,int y)
{
makeroot(x);
access(y);
splay(x,0);
t[x][1]=fa[y]=pf[y]=0;
update(x);
}
void bfs(int x)
{
queue<int> que;
while (!que.empty())que.pop();
que.push(x),b[tot=1]=x;
while (!que.empty())
{
int now=que.front();
que.pop();
for (int i=0;i<=1;i++)
{
if (t[now][i])que.push(t[now][i]),b[++tot]=t[now][i];
if (tot>50)break;
}
if (tot>50)break;
}
}
int main()
{
freopen("triangle.in","r",stdin);
freopen("triangle.out","w",stdout);
n=read(),q=read();
for (int i=1;i<=n;i++)a[i].val=readll();
for (int i=2;i<=n;i++)
{
fat[i]=read();
link(i,fat[i]);
update(i);
}
while (q--)
{
int z=read(),x=read();
if (z==1)
{
int y=read();
makeroot(y);
access(x);
splay(x,0);
bfs(x);
if (tot>50)printf("Y\n");
else
{
bool bz=0;
sort(b+1,b+tot+1,cmp);
for (int i=1;i<=tot-2;i++)
{
if (a[b[i]].val+a[b[i+1]].val>a[b[i+2]].val)
{
bz=1;
break;
}
}
printf(bz?"Y\n":"N\n");
}
}
else if (z==2)a[x].val=readll();
else
{
int y=read();
if (x==y)continue;
makeroot(1);
access(y);
splay(x,0);
if (getroot(y)==x)
{
cut(y,fat[y]),link(y,x);
fat[y]=x;
}
else
{
cut(x,fat[x]),link(x,y);
fat[x]=y;
}
}
}
return 0;
}