前言
爲了降爲Noip難度,好心出題人悄悄把數據改成了隨機,這樣樹高就是log
題面
給定一棵樹與他的根,根標號是0,有n+1個點。
現有一些信息在樹上傳遞,每一個信息在樹上兩個節點傳遞的時間都是1s。
現每一個節點除了根有兩種狀態。
- 普通狀態:可以上傳信息,下傳信息。
- 懵逼狀態只能下傳信息。
一開始所有點都是普通狀態,當一個點上傳信息後變爲懵逼狀態,當一個點接受了下傳的信息後變爲普通狀態。某一時刻懵逼狀態的點有下傳到自己的信息又有上傳到自己的信息,先計算下傳的信息,使自己解除懵逼,再上傳信息。某一時刻如果一個非懵逼的點接受到多條信息,上傳那一個來源點(注:來源點是一開始上傳這條信息的點,即題目中給出的這條信息的出發點)標號最小的,然後進入懵逼狀態。一個信息上傳到懵逼的點,懵逼的點先接受到信息,然後下傳。
上傳是兒子給父親信息,下傳是父親向信息來源點方向的兒子下傳信息。
一條信息重新回到來源點稱作該信息完成傳遞。現在給出m條信息的來源點,出發時間,要求出這m個信息的分別的完成時間。
sol
題面有點扯不清楚,我已經儘量詳細的翻譯了
這道題一看就知道要確定某條信息從那個點開始下傳(稱這個點爲轉折點)。一般是根(0號點),但是很有可能中途就返回了。一般來說,就是某一條信息自己完成後會對他經過的路徑造成影響。我們可以搞一個這樣的思路:找到當前的點的轉折點,然後算出答案,然後對他的路徑進行某些值的修改。
這樣就要求後面的點不能影響到前面的的點。
如何做到?
考慮兩個點,如果兩個點,誰的deep[x]+t[a](t[a]是出發時間)小,誰就會在到達某一相同高度時當前時間較小,所以按這個排序就可以了。
然後就是對於任何一個點x
如果
b是之前影響到x的信息的來源點,T是結束時間,t是開始時間,那麼a到了x就要返回。那麼肯定是二分找最淺的x。這樣在樹上,就可以使用樹鏈剖分.
但是如果在最外邊二分深度,裏面 查詢,就會TLE所以我們換一個搞法,就是往上面跳重鏈,對於一條重鏈直接查詢,如果該重鏈內有大於deep[a]+t[a]的,再在這一截線段樹上用二分,否則跳上一個重鏈。
code
#include<bits/stdc++.h>
using namespace std;
inline char gc(){
static char buf[1<<6],*p1=buf,*p2=buf;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<6,stdin),p1==p2)?EOF:*p1++;
}
template <class T>
inline void read(T&data){
data=0;
register char ch=0;
while(ch< '0'|| ch>'9')ch=gc();
while(ch<='9' && ch >='0'){
data=(data<<1) + (data<<3)+(ch&15);
ch=gc();
}
return;
}
template <class R>
inline void write(R data){
if(data>9)write(data/10);
putchar(data%10+'0');
}
const int _ = 2e5+19,INF = 2e9;
int n,m,dep[_],fa[_],to[_],nxt[_],fir[_],cnt_edge,cnt,dfn[_],fdfn[_],son[_],Size[_],top[_],Tree[_<<2],Lazy[_<<2];
int ans[_],Dep[_<<2];
inline void add(register int a,register int b){to[++cnt_edge]=b,nxt[cnt_edge]=fir[a],fir[a]=cnt_edge;}
struct me{
int u,Ti,id;
}qq[_];
void Dfs(int now){
dep[now]=dep[fa[now]]+1;
for(register int i=fir[now];i;i=nxt[i]){
if(to[i]==fa[now])continue;
Dfs(to[i]);
son[now] = Size[son[now]]<Size[to[i]]?to[i]:son[now];Size[now]+=Size[to[i]];
}
++ Size[now];
}
void dfs(int now,int topf){
dfn[now]=++cnt,fdfn[cnt]=now,top[now]=topf;
if(son[now])dfs(son[now],topf);
for(register int i=fir[now];i;i=nxt[i]){
if(to[i]==son[now]||to[i]==fa[now])continue;
dfs(to[i],to[i]);
}
return;
}
inline void update(register int qp){ Tree[qp]=max(Tree[qp<<1],Tree[qp<<1|1]);return;}
inline void pushdown(register int qp){
if(Lazy[qp]!=-INF){
Tree[qp<<1]=max(Tree[qp<<1],Dep[qp<<1]*2+Lazy[qp]);
Lazy[qp<<1]=max(Lazy[qp<<1],Lazy[qp]);
Tree[qp<<1|1]=max(Tree[qp<<1|1],Dep[qp<<1|1]*2+Lazy[qp]);
Lazy[qp<<1|1]=max(Lazy[qp<<1|1],Lazy[qp]);
}
Lazy[qp]=-INF;return;
}
void Build(int l,int r,register int qp){
Tree[qp]=Lazy[qp]=-INF;
if(l==r){Lazy[qp]=Tree[qp]=-INF;Dep[qp]=dep[fdfn[l]];return;}
int mid = l+r>>1;
Build(l,mid,qp<<1),Build(mid+1,r,qp<<1|1);
update(qp);
Dep[qp]=max(Dep[qp<<1],Dep[qp<<1|1]);
return;
}
int Query(const int l,const int r,int now_l,int now_r,int qp){
if(l<=now_l&&r>=now_r){return Tree[qp];}
int mid=now_l+now_r>>1;
pushdown(qp);
if(r<=mid) return Query(l,r,now_l,mid,qp<<1);
if(l>mid) return Query(l,r,mid+1,now_r,qp<<1|1);
return max( Query(l,r,now_l,mid,qp<<1),Query(l,r,mid+1,now_r,qp<<1|1) );
}
void fix(const int l,const int r,int now_l,int now_r,int qp,const int zh){
if(l<=now_l&&r>=now_r){Tree[qp]=max(Tree[qp],zh+2*Dep[qp]),Lazy[qp]=max(Lazy[qp],zh);return;}
register int mid = now_l+now_r>>1;
pushdown(qp);
if(l<=mid) fix(l,r,now_l,mid,qp<<1,zh);
if(r>mid) fix(l,r,mid+1,now_r,qp<<1|1,zh);
update(qp);return;
}
inline int pre_query(register int a,register int ta,int ki){
register int u=a,l=1,r,mid,Ans=0 ;
while(u){
if(Query(dfn[top[u]],dfn[u],1,n,1 )<= dep[a]+ta)u=fa[top[u]];
else {
l = dfn[u], r=dfn[top[u]],mid;
register int uk=0;
while(r<=l){
mid = l+r>>1;
if(Query(mid,l,1,n,1)>dep[a]+ta)r=mid+1,uk=mid;
else l=mid-1;
}
if(uk)l=uk;
break;
}
}
l=fdfn[l],u=a;
Ans=ta+(dep[a]-dep[l])*2;
while(top[u]^top[l]){
fix(dfn[top[u]],dfn[u],1,n,1,Ans-dep[a]);
u=fa[top[u]];
}
fix(dfn[l],dfn[u],1,n,1,Ans-dep[a]);
return Ans;
}
inline bool cmp1(register me a,register me b){
if(dep[a.u]+a.Ti!=dep[b.u]+b.Ti)return dep[a.u]+a.Ti<dep[b.u]+b.Ti;
return a.u<b.u;
}
int main(){
freopen("message.in","r",stdin);
freopen("message.out","w",stdout);
read(n),read(m);++n;
if(m==0)return 0;
for(register int i=2,a;i<=n;++i){
read(a);++a,add(a,i),add(i,a),fa[i]=a;
}
Dfs(1);dfs(1,1);Build(1,n,1);
for(register int i=1;i<=m;++i)
read(qq[i].u),read(qq[i].Ti),qq[i].id=i,qq[i].u++;
sort(qq+1,qq+m+1,cmp1);
for(register int i=1;i<=m;++i){
ans[qq[i].id]=pre_query(qq[i].u,qq[i].Ti,i);
}
for(register int i=1;i<=m;++i){
write(ans[i]);
puts("");
}return 0;
}