Message 【題解】【考試】

前言

爲了降爲Noip難度,好心出題人悄悄把數據改成了隨機,這樣樹高就是log

題面

給定一棵樹與他的根,根標號是0,有n+1個點。
現有一些信息在樹上傳遞,每一個信息在樹上兩個節點傳遞的時間都是1s。
現每一個節點除了根有兩種狀態。

  • 普通狀態:可以上傳信息,下傳信息。
  • 懵逼狀態只能下傳信息。

一開始所有點都是普通狀態,當一個點上傳信息後變爲懵逼狀態,當一個點接受了下傳的信息後變爲普通狀態。某一時刻懵逼狀態的點有下傳到自己的信息又有上傳到自己的信息,先計算下傳的信息,使自己解除懵逼,再上傳信息。某一時刻如果一個非懵逼的點接受到多條信息,上傳那一個來源點(注:來源點是一開始上傳這條信息的點,即題目中給出的這條信息的出發點)標號最小的,然後進入懵逼狀態。一個信息上傳到懵逼的點,懵逼的點先接受到信息,然後下傳。
上傳是兒子給父親信息,下傳是父親向信息來源點方向的兒子下傳信息。
一條信息重新回到來源點稱作該信息完成傳遞。現在給出m條信息的來源點,出發時間,要求出這m個信息的分別的完成時間。

sol

題面有點扯不清楚,我已經儘量詳細的翻譯了
這道題一看就知道要確定某條信息從那個點開始下傳(稱這個點爲轉折點)。一般是根(0號點),但是很有可能中途就返回了。一般來說,就是某一條信息自己完成後會對他經過的路徑造成影響。我們可以搞一個這樣的思路:找到當前的點的轉折點,然後算出答案,然後對他的路徑進行某些值的修改。
這樣就要求後面的點不能影響到前面的的點。
如何做到?
考慮兩個點,如果兩個點,誰的deep[x]+t[a](t[a]是出發時間)小,誰就會在到達某一相同高度時當前時間較小,所以按這個排序就可以了。
然後就是對於任何一個點x
如果

deep[a]+t[a]deep[x]<T[b]deep[b]+2deep[x]

b是之前影響到x的信息的來源點,T是結束時間,t是開始時間,那麼a到了x就要返回。那麼肯定是二分找最淺的x。這樣在樹上,就可以使用樹鏈剖分.
但是如果在最外邊二分深度,裏面log2 查詢,就會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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章