1. 程式人生 > >P3066 [USACO12DEC]逃跑的BarnRunning Away From

P3066 [USACO12DEC]逃跑的BarnRunning Away From

目錄

題目

luoguP3066

思路

雖說這個題目有多種做法,但
左偏樹演算法:
我們發現這個合併的時候並不好合並,因為存的值不是固定的
那我們是不是可以lazy陣列呢
因為是兩個顆樹合併,顯然是步闊以的
那就轉換一下思路,什麼是固定的呢
那就是1到i的路徑
我們可以dfs出val[i]表示1到i的路徑和
這個val也就是左偏樹的初始值
然後我們發現,一個樹i的所有後代x
都要經過1到i的所經過的路徑
所以直接維護val,只需要在比較的時候減去val[i]即可
感覺我說的太噁心了,還是去看程式碼吧

錯誤&&注意

這個空間和long long讓我wrong了4次,小心點吧

程式碼

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn=200007;
typedef long long ll;
inline ll read() {
    ll x=0,f=1;char s=getchar();
    for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    return  x*f;
}
struct edge {
    int v,nxt;
    ll q;
}e[maxn<<1];
int head[maxn<<1],tot;
void add_edge(int u,int v,ll q) {
    e[++tot].v=v;
    e[tot].q=q;
    e[tot].nxt=head[u];
    head[u]=tot;
}
int n;
ll m,val[maxn];
int ans[maxn],size[maxn];
int ch[maxn][2],dis[maxn];
int merge(int x,int y) {
    if(!x||!y) return x+y;
    if(val[x]<val[y]) swap(x,y);
    ch[x][1]=merge(ch[x][1],y);
    if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]);
    dis[x]=dis[ch[x][1]]+1;
    return x;
}
int work1(int x,int y) {
    int tmp=merge(x,y);
    y=x^y^tmp;
    x=tmp;
    size[x]+=size[y];
    return tmp;
}
int work2(int x) {
    int tmp=merge(ch[x][0],ch[x][1]);
    size[tmp]=size[x]-1;
    return tmp;
}
int dfs(int u,int f) {
    ans[u]=1;
    int rt=u;
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v==f) continue;
        int tmp=dfs(v,u);
        rt=work1(rt,tmp);
    }
    while(val[rt]-val[u] > m) rt=work2(rt);
    ans[u]=size[rt];
    return rt;
}
void nb_dfs(int u,int f) {
    size[u]=1;
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].v;
        if(v==f) continue;
        val[v]=val[u]+e[i].q;
        nb_dfs(v,u);
    }
}
int main() {
    n=read(),m=read();
    FOR(i,2,n) {
        int x=read();
        ll y=read();
        add_edge(i,x,y);
        add_edge(x,i,y);
    }
    nb_dfs(1,0);
    dfs(1,0);
    FOR(i,1,n) cout<<ans[i]<<"\n";
    return  0;
}