納屋から逃げて[Usaco2012 12月]

タイトル説明

1点は、ルート付きツリーのルートとして指定されたサブツリー内の各点を尋ね、その距離は、点Lの数に等しい未満です。

入力形式

行1:2つの整数、N及びL(1 <= N <= 200,000 1 <= L <= 10 ^ 18)

行2..N:i番目の行は、二つの整数P_IとL_iをが含まれています。P_I(1 <= P_I <i)はiと納屋、及びL_iを(1 <= L_iを<= 10 ^ 12)は、その経路の長さである牧草地との間の最短経路上の最初の牧草地です。

出力フォーマット

行1..N:1行に1つの番号、私は離れて、その合計の長さLを超えていない納屋(牧草1)から厳密に遠くつながる道路を取ることによって、牧草地から到達可能な数の牧草地であるライン上の番号


この質問は、多くの先進的な練習を持っていますしかし、私はしません

我々は、トピックが結論に達することができる分析 - 現在のノードuのため、uがすべての祖先の点の距離よりも大きい距離U Lのサブツリーは、U L(Uも祖先)よりも大きいです。各ノードuのための私達の考えるやすいので、我々は最初にその祖先のANC U Lよりも長い距離を計算し、先祖のために、その答えは、サイズ(U)を差し引きます。ノードは、ツリーの子ノードの各点を初期化する回答をサブツリーの大きさを表します。得られた結合特性は、その前に、私たちはプレフィックスツリーを使用して思ったことができ、この減算サイズ行き蓄積(U)ANCの祖先。

しかし、あなたはダイレクトが問題視ことがわかります。

まずuのために、それANCを行うには、拠出の(U)を-sizeに答える、と私たちはANCの祖先が行く蓄積たい貢献です。その後、我々は、このようなuのFA(U)の父としてuの先祖のために、(u)の第一及びFAはANCの祖先であったに違いない距離lの祖先よりも大きいことがわかったが、我々は-sizeます(FA(U))プラスこの祖先に、その答えの祖先は、-size(u)は、答えは明らかに間違っている二倍蓄積しています。それを避けるためにどのように?簡単に言えば、我々は大きさ(FA(U))マイナスサイズ(u)ができます。その後、問題が解決されます。

シークの最初の距離lの祖先よりも大きい場合、我々は乗算を行うことができ、その後、合計時間の複雑さはO(NlogN)です。

*レコードサイズにサイズ(FA(U))が減算されるサイズ(U)元のサイズ、そのポイントサイズで(u)があったかもしれないマイナスいくつかの子ノードU、私たち再びオープン配列元のサイズ。

*父親を見て、長い長いを開けないでください

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define maxn 200001
using namespace std;
 
struct edge{
    int to,next; long long dis;
    edge(){}
    edge(const int &_to,const long long &_dis,const int &_next){ to=_to,dis=_dis,next=_next; }
}e[maxn<<1];
int head[maxn],k;
 
int fa[maxn][20],size[maxn],size2[maxn],sum[maxn],maxdep;
int n;
long long m,dis[maxn][20];
 
inline long long read(){
    register long long x(0),f(1); register char c(getchar());
    while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
    while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
inline void add(const int &u,const int &v,const long long &w){ e[k]=edge(v,w,head[u]),head[u]=k++; }
 
void dfs(int u){
    size[u]=1;
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v==fa[u][0]) continue;
        fa[v][0]=u,dis[v][0]=e[i].dis;
        for(register int j=1;j<=maxdep;j++) fa[v][j]=fa[fa[v][j-1]][j-1],dis[v][j]=dis[v][j-1]+dis[fa[v][j-1]][j-1];
        dfs(v),size[u]+=size[v];
    }
}
 
void dfs_getsum(int u){
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v==fa[u][0]) continue;
        dfs_getsum(v);
        long long len=0; int tmp=size[v],tmp2=size2[v];
        for(register int j=maxdep;j>=0;j--) if(len+dis[v][j]<=m&&fa[v][j]) len+=dis[v][j],v=fa[v][j];
        if(len+dis[v][0]>m&&fa[v][0]) sum[fa[v][0]]+=tmp,size[u]-=tmp2;
    }
}
 
void dfs_getans(int u){
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v==fa[u][0]) continue;
        dfs_getans(v),sum[u]+=sum[v];
    }
}
 
int main(){
    memset(head,-1,sizeof head);
    n=read(),m=read();
    for(register int i=2;i<=n;i++){
        int v=read(); long long w=read();
        add(i,v,w),add(v,i,w);
    }
    maxdep=(int)log(n)/log(2),dfs(1);
    for(register int i=1;i<=n;i++) size2[i]=size[i];
     
    dfs_getsum(1);
    dfs_getans(1);
     
    for(register int i=1;i<=n;i++) printf("%d\n",size2[i]-sum[i]);
    return 0;
}

おすすめ

転載: www.cnblogs.com/akura/p/10945606.html