洛谷P4271【USACO18FEB】New Barns

       来来来,先放个链接:https://www.luogu.org/problemnew/show/P4271


       在家里颓得时间长了,都不知道该做什么题了,于是随便找道USACO的水题刷一刷吧。

       大佬们太强了,随手就用什么动态淀粉质切了,可蒟蒻只能把它当做数据结构裸题做,因为蒟蒻只能想到树剖QWQ(其实是只会)

       博主觉得这题树剖的思路还是蛮显然的,可我还是调了两个小时,首先,很明显在任意时刻这个图一定是个森林(证明略),其次,由于这题并没有要求强制在线,我们可以先读入整棵树进行树剖后在从头到尾进行处理。要知道与 x x 距离最远的点与它的距离,无非就是对于x的每个祖先,找到一个不在 x x 属于的子树的最低点y,然后求出 x,y x , y 的距离取个最大值。那么直接就可以上树剖啦!

       我们用 mxdi m x d i 表示 i i 节点的当前子树中最深点的深度,令mxvi=mxdi2×depi+2,那么

ans=max(max{mxvi}+depx,(i(path:rootx)subtreex,isubtreeroot),max(depxdeproot,mxdxdepx)) a n s = m a x ( m a x { m x v i } + d e p x , ( i ∉ ( p a t h : r o o t → x ) ∪ s u b t r e e x , i ∈ s u b t r e e r o o t ) , m a x ( d e p x − d e p r o o t , m x d x − d e p x ) )

       为了防止出锅,我们将每个root的初始深度赋为 2 2 。然后怎么做就不用说了吧。时间复杂度Θ(qlog2q)

       我的代码:

#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;
} 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值