所以 Chinese Round 出 DS 是传统了对吧。
Description
Link.
Given is a rooted tree with the \(\sf1\)-th node as the root.
The tree will be given in this way: it will tell you that the parent of the \(\sf i\)-th node is \(a_{i}\).
Supporting the following operations:
-
1 l r x
: let \(\sf \forall i\in[l,r],a_{i}=max\{a_{i}-x,1\}\). -
2 u v
: find the LCA (Lowest Common Ancestor) of \(\sf u\) and \(\sf v\).
Solution
经典永流传。
考虑到修改操作是对结点进行的操作,然后这个东西不太能直接 LCT 或树剖,考虑照序列来分块,那么我们来对结点编号分块。
- 修改;
\(\quad\)维护一个属性 \(\sf top_{u}\) 表示在原树上结点 \(\sf u\) 的祖先中不和 \(\sf u\) 在同一个块里面的编号最大的一个结点的编号,如果不存在的话就令 \(\sf top_{u}=1\)。这样的话你从结点 \(\sf u\) 跳到 root 的复杂度为 \(\sf O(\sqrt{n})\)。接下来考虑怎么维护这个东西。
\(\quad\)散块我们直接暴力扫着改;对于整块,可以发现如果一个块的被修改次数超过了块的大小,那么就一定会有 \(\sf top_{u}=fa_{u}\)。
- 询问。
\(\quad\)分三个类讨论,这个比较好做(差不多和树剖找 LCA 一个样子)。
#include<bits/stdc++.h>
using namespace std;
int n,m,top[100010],deln[320],tag[320],belong[100010],bl[320],br[320],fa[100010],bs;
#define gtlf(x) ((x-1)*bs+1)
#define gtrg(x) (min(x*bs,n))
void updtop(int x)
{
if(belong[x]^belong[fa[x]]) top[x]=fa[x];
else top[x]=top[fa[x]];
}
void turndown(int x)
{
if(tag[x])
{
for(int i=gtlf(x);i<=gtrg(x);++i) fa[i]=max(fa[i]-tag[x],1);
tag[x]=0;
}
}
int main()
{
scanf("%d %d",&n,&m),bs=sqrt(double(n))+1,fa[1]=belong[1]=1;
for(int i=2;i<=n;++i) scanf("%d",&fa[i]);
for(int i=2;i<=n;++i) belong[i]=(i-1)/bs+1,updtop(i);
while(m--)
{
int opt; scanf("%d",&opt);
if(opt==1)
{
int opl,opr,opx;
scanf("%d %d %d",&opl,&opr,&opx);
turndown(belong[opl]);
if(belong[opl]==belong[opr])
{
turndown(belong[opl]);
for(int i=opl;i<=opr;++i) fa[i]=max(fa[i]-opx,1),updtop(i);
for(int i=opr+1;i<=gtrg(belong[opl]);++i) updtop(i);
}
else
{
turndown(belong[opl]);
for(int i=opl;i<=gtrg(belong[opl]);++i) fa[i]=max(fa[i]-opx,1),updtop(i);
for(int i=gtlf(belong[opl]);i<opl;++i) updtop(i);
turndown(belong[opr]);
for(int i=gtlf(belong[opr]);i<=opr;++i) fa[i]=max(fa[i]-opx,1),updtop(i);
for(int i=opr+1;i<=gtrg(belong[opr]);++i) updtop(i);
for(int i=belong[opl]+1;i<belong[opr];++i)
{
if(deln[i]>=bs) tag[i]+=opx;
else
{
++deln[i];
for(int j=gtlf(i);j<=gtrg(i);++j) fa[j]=max(fa[j]-opx,1),updtop(j);
}
}
}
}
else
{
int opx,opy; scanf("%d %d",&opx,&opy);
while(opx^opy)
{
int fopx,fopy;
if(deln[belong[opx]]>=bs) turndown(belong[opx]),fopx=fa[opx];
else fopx=top[opx];
if(deln[belong[opy]]>=bs) turndown(belong[opy]),fopy=fa[opy];
else fopy=top[opy];
if(belong[opx]^belong[opy])
{
if(belong[opx]>belong[opy]) opx=fopx;
else opy=fopy;
}
else if(fopx^fopy) opx=fopx,opy=fopy;
else
{
if(opx>opy) turndown(belong[opx]),opx=fa[opx];
else turndown(belong[opy]),opy=fa[opy];
}
}
printf("%d\n",opx);
}
}
return 0;
}