标签:ring top code 标准 规律 algo bool string get
首先我们考虑事件发生的真正的先后顺序
我们考虑在某一个点$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$的信息需要经过$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\n",ret[i]); return 0; }
标签:ring top code 标准 规律 algo bool string get
原文地址:https://www.cnblogs.com/zhangleo/p/11112551.html