来来来,先放个链接:https://www.luogu.org/problemnew/show/P4271
在家里颓得时间长了,都不知道该做什么题了,于是随便找道USACO的水题刷一刷吧。
大佬们太强了,随手就用什么动态淀粉质切了,可蒟蒻只能把它当做数据结构裸题做,因为蒟蒻只能想到树剖QWQ(其实是只会)。
博主觉得这题树剖的思路还是蛮显然的,可我还是调了两个小时,首先,很明显在任意时刻这个图一定是个森林(证明略),其次,由于这题并没有要求强制在线,我们可以先读入整棵树进行树剖后在从头到尾进行处理。要知道与
x
x
距离最远的点与它的距离,无非就是对于的每个祖先,找到一个不在
x
x
属于的子树的最低点,然后求出
x,y
x
,
y
的距离取个最大值。那么直接就可以上树剖啦!
我们用 mxdi m x d i 表示 i i 节点的当前子树中最深点的深度,令,那么
为了防止出锅,我们将每个root的初始深度赋为 2 2 。然后怎么做就不用说了吧。时间复杂度。
我的代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<vector>
using namespace std;
int n,q;
vector<int>G[100010];
int sz[100010];
int dep[100010];
int sps[100010];
int rt[100010];
int seq[100010];
int par[100010];
int top[100010];
int ind[100010];
int cnt;
vector<pair<int,int> >que;
vector<int>root;
char In()
{
char x=getchar();
while(x!='B' && x!='Q')x=getchar();
return x;
}
void dfs(int x,int p)
{
top[x]=p;
sz[x]=1;
for(int i=0;i<G[x].size();i++)
{
int y=G[x][i];
par[y]=x;
dep[y]=dep[x]+1;
dfs(y,p);
sz[x]+=sz[y];
}
}
void HLD(int x,int lst)
{
seq[++cnt]=x;
ind[x]=cnt;
rt[x]=lst;
if(sps[x])HLD(sps[x],lst);
for(int i=0;i<G[x].size();i++)
{
int y=G[x][i];
if(sps[x]==y)continue;
HLD(y,y);
}
}
namespace sgt
{
int chg[200010],mxd[200010],mxv[200010],son[200010][2],root,Cnt;
void pushdown(int x)
{
if(chg[x]>mxd[x])
{
mxv[x]+=chg[x]-mxd[x];
mxd[x]=chg[x];
}
if(!son[x][0] && !son[x][1])return;
chg[son[x][0]]=max(chg[son[x][0]],chg[x]);
chg[son[x][1]]=max(chg[son[x][1]],chg[x]);
}
void pushup(int x)
{
if(!son[x][0] && !son[x][1])return;
mxd[x]=max(mxd[son[x][0]],mxd[son[x][1]]);
mxv[x]=max(mxv[son[x][0]],mxv[son[x][1]]);
}
void build(int &x,int l,int r)
{
x=++Cnt;
if(l==r)
{
mxv[x]=-2*dep[seq[l]]+2;
return;
}
int mid=(l+r)>>1;
build(son[x][0],l,mid);
build(son[x][1],mid+1,r);
pushup(x);
}
void update(int a,int b,int k,int l,int r,int v)
{
if(a>b || l>r)return;
pushdown(k);
if(a==l && b==r)
{
chg[k]=max(chg[k],v);
pushdown(k);
}
else
{
int mid=(l+r)>>1;
if(b<=mid)pushdown(son[k][1]),update(a,b,son[k][0],l,mid,v);
else if(a>mid)pushdown(son[k][0]),update(a,b,son[k][1],mid+1,r,v);
else update(a,mid,son[k][0],l,mid,v),update(mid+1,b,son[k][1],mid+1,r,v);
pushup(k);
}
}
int query(int a,int b,int k,int l,int r)
{
if(a>b || l>r)return -1e9;
pushdown(k);
if(a==l && b==r)return mxv[k];
int mid=(l+r)>>1;
if(b<=mid)return query(a,b,son[k][0],l,mid);
else if(a>mid)return query(a,b,son[k][1],mid+1,r);
return max(query(a,mid,son[k][0],l,mid),query(mid+1,b,son[k][1],mid+1,r));
}
int Q(int x,int k,int l,int r)
{
pushdown(k);
if(l==r)return mxd[k];
int mid=(l+r)>>1;
if(x<=mid)return Q(x,son[k][0],l,mid);
else return Q(x,son[k][1],mid+1,r);
}
}
int main()
{
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
if(In()=='B')
{
int x;
scanf("%d",&x);
n++;
if(x==-1)root.push_back(n);
else G[x].push_back(n);
que.push_back(make_pair(1,n));
}
else
{
int x;
scanf("%d",&x);
que.push_back(make_pair(2,x));
}
}
for(int i=0;i<root.size();i++)dep[root[i]]=2,dfs(root[i],root[i]);
for(int i=1;i<=n;i++)
{
for(int j=0;j<G[i].size();j++)
{
if(!sps[i] || sz[G[i][j]]>sz[sps[i]])sps[i]=G[i][j];
}
}
for(int i=0;i<root.size();i++)HLD(root[i],root[i]);
sgt::build(sgt::root,1,n);
for(int i=0;i<que.size();i++)
{
int op=que[i].first,x=que[i].second;
if(op==1)
{
int d=dep[x];
while(rt[x]!=top[x])
{
sgt::update(ind[rt[x]],ind[x],sgt::root,1,n,d);
x=par[rt[x]];
}
sgt::update(ind[top[x]],ind[x],sgt::root,1,n,d);
}
else
{
int d=dep[x];
int ans=max(d-2,sgt::Q(ind[x],sgt::root,1,n)-d);
int res=sgt::query(ind[x]+sz[x],ind[top[x]]+sz[top[x]]-1,sgt::root,1,n);
int lst=-1;
while(rt[x]!=top[x])
{
if(lst!=-1)res=max(res,sgt::query(ind[x]+1,lst,sgt::root,1,n));
lst=ind[rt[x]]-1;
x=par[rt[x]];
}
if(lst!=-1)res=max(res,sgt::query(ind[x]+1,lst,sgt::root,1,n));
ans=max(ans,res+d);
printf("%d\n",ans);
}
}
return 0;
}