CF725G

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

我们考虑在某一个点$f$的子树内有两点$i$,$j$先后在$t_{i}$,$t_{j}$两个时间向上发送信息

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

推个小式子:设$i$先到达$f$,那么一定要满足的条件是$dep_{i}-dep_{f}+t_{i}$<$dep_{j}-dep_{f}+t_{j}$

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

一个事件在另一个事件之前产生影响的条件是$dep_{i}+t_{i}<dep_{j}+t_{j}$

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

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

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

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

也即当$dep_{i}-dep_{f}+t_{i}>2dep_{p}+t_{p}-(dep_{p}-dep_{f})$时,$i$的信息可以经过$f$

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

整理一下,能够得到:$dep_{i}+t_{i}>dep_{p}+t_{p}+2dep_{f}$

$dep_{f}$始终不变,$dep_{p}+t_{p}$只与$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
",ret[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/zhangleo/p/11112551.html