CF725G

首先我们考虑事件发生的真正的先后顺序

我们考虑在某一个点f的子树内有两点ij先后在ti,tj两个时间向上发送信息

那么两者谁会先传到f呢?

推个小式子:设i先到达f,那么一定要满足的条件是depidepf+ti<depjdepf+tj

发现这个不等式与f无关,因此可以推出一般规律:

一个事件在另一个事件之前产生影响的条件是depi+ti<depj+tj

因此我们按这一标准对所有询问排序,这样只需从前向后处理即可

接下来我们考虑一个点向上最多能跳到哪:

首先不难发现:如果一个点f正在等待发源于点p的信息的回复,那么这个f将等到2depp+tp(deppdepf),也就是说在这个时间点之前f都将在等待p的信息的回复(这里我们假设i的信息传递到了根,否则的话需要去掉实际到达的点的深度)

假设我们有一个来自于i的信息需要经过f,那么我们只需比较这条信息到达f的时间点与上面那个时间点的关系就能知道是否可以经过f

也即当depidepf+ti>2depp+tp(deppdepf)时,i的信息可以经过f

可是这个东西乱七八糟的怎么搞嘛!

整理一下,能够得到:depi+ti>depp+tp+2depf

depf始终不变,depp+tp只与p有关,用线段树维护树剖即可,查询时在链上二分右侧那堆东西的最大值

贴代码:

复制代码
#include <cstdio>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#define rt1 rt<<1
#define rt2 (rt<<1)|1
using namespace std;
struct Seg_tree
{
    int maxv,ori,lazy;
}tree[800005];
int dep[200005],nnum[200005],onum[200005],ttop[200005],f[200005],siz[200005],son[200005];
struct Ques
{
    int p,t,num;
    friend bool operator < (Ques a,Ques b)
    {
        return dep[a.p]+a.t==dep[b.p]+b.t?a.p<b.p:dep[a.p]+a.t<dep[b.p]+b.t;
    }
}q[200005];
vector <int> v[200005];
int ret[200005];
int n,m,tot;
void dfs(int x,int fx)
{
    siz[x]=1,dep[x]=dep[fx]+1,f[x]=fx;
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        if(to==fx)continue;
        dfs(to,x);
        siz[x]+=siz[to],son[x]=(siz[to]>siz[son[x]])?to:son[x];
    }
}
void redfs(int x,int fx,int topx)
{
    ttop[x]=topx,nnum[x]=++tot,onum[tot]=x;
    if(son[x])redfs(son[x],x,topx);
    for(int i=0;i<v[x].size();i++)
    {
        int to=v[x][i];
        if(to==fx||to==son[x])continue;
        redfs(to,x,to);
    }
}
void buildtree(int rt,int l,int r)
{
    tree[rt].maxv=tree[rt].lazy=-0x3f3f3f3f;
    if(l==r)
    {
        tree[rt].ori=dep[onum[l]]<<1;
        return;
    }
    int mid=(l+r)>>1;
    buildtree(rt1,l,mid),buildtree(rt2,mid+1,r);
    tree[rt].ori=max(tree[rt1].ori,tree[rt2].ori);
}
void pushdown(int rt)
{
    tree[rt1].lazy=max(tree[rt1].lazy,tree[rt].lazy);
    tree[rt2].lazy=max(tree[rt2].lazy,tree[rt].lazy);
    tree[rt1].maxv=max(tree[rt1].maxv,tree[rt1].ori+tree[rt].lazy);
    tree[rt2].maxv=max(tree[rt2].maxv,tree[rt2].ori+tree[rt].lazy);
    tree[rt].lazy=-0x3f3f3f3f;
}
void update(int rt,int l,int r,int lq,int rq,int v)
{
    if(l>=lq&&r<=rq)
    {
        tree[rt].lazy=max(tree[rt].lazy,v);
        tree[rt].maxv=max(tree[rt].maxv,tree[rt].ori+v);
        return;
    }
    if(tree[rt].lazy!=-0x3f3f3f3f)pushdown(rt);
    int mid=(l+r)>>1;
    if(lq<=mid)update(rt1,l,mid,lq,rq,v);
    if(rq>mid)update(rt2,mid+1,r,lq,rq,v);
    tree[rt].maxv=max(tree[rt1].maxv,tree[rt2].maxv);
}
int query(int rt,int l,int r,int lq,int rq)
{
    if(l>=lq&&r<=rq)return tree[rt].maxv;
    if(tree[rt].lazy!=-0x3f3f3f3f)pushdown(rt);
    int mid=(l+r)>>1;
    int s=-0x3f3f3f3f;
    if(lq<=mid)s=max(s,query(rt1,l,mid,lq,rq));
    if(rq>mid)s=max(s,query(rt2,mid+1,r,lq,rq));
    return s;
}
int solve(int p,int tim)
{
    int u=p;
    while(u)
    {
        int t=ttop[u];
        if(query(1,1,n,nnum[t],nnum[u])<=dep[p]+tim){u=f[ttop[u]];continue;}
        int l=nnum[t],r=nnum[u],ans=r;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(query(1,1,n,mid,r)>dep[p]+tim)ans=mid,l=mid+1;
            else r=mid-1;
        }
        u=onum[ans];break;
    }
    if(!u)u=1;
    int re=2*(dep[p]-dep[u])+tim;
    int tp=p;
    while(ttop[tp]!=ttop[u])update(1,1,n,nnum[ttop[tp]],nnum[tp],re-dep[p]),tp=f[ttop[tp]];
    update(1,1,n,nnum[u]+1,nnum[tp],re-dep[p]);
    return re;
}
inline int read()
{
    int f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main()
{
    n=read()+1,m=read();
    for(int i=2;i<=n;i++)f[i]=read()+1,v[f[i]].push_back(i);
    dfs(1,0),redfs(1,0,1),buildtree(1,1,n);
    for(int i=1;i<=m;i++)q[i].p=read()+1,q[i].t=read(),q[i].num=i;
    sort(q+1,q+m+1);
    for(int i=1;i<=m;i++)ret[q[i].num]=solve(q[i].p,q[i].t);
    for(int i=1;i<=m;i++)printf("%d\n",ret[i]);
    return 0;
}
复制代码

 

posted @   lleozhang  Views(262)  Comments(0Edit  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
levels of contents
点击右上角即可分享
微信分享提示