1. 程式人生 > >[USACO12DEC] 逃跑的BarnRunning Away From…(主席樹)

[USACO12DEC] 逃跑的BarnRunning Away From…(主席樹)

[USACO12DEC]逃跑的BarnRunning Away From…

題目描述

It's milking time at Farmer John's farm, but the cows have all run away! Farmer John needs to round them all up, and needs your help in the search.

FJ's farm is a series of N (1 <= N <= 200,000) pastures numbered 1...N connected by N - 1 bidirectional paths. The barn is located at pasture 1, and it is possible to reach any pasture from the barn.

FJ's cows were in their pastures this morning, but who knows where they ran to by now. FJ does know that the cows only run away from the barn, and they are too lazy to run a distance of more than L. For every pasture, FJ wants to know how many different pastures cows starting in that pasture could have ended up in.

Note: 64-bit integers (int64 in Pascal, long long in C/C++ and long in Java) are needed to store the distance values.

給出以1號點為根的一棵有根樹,問每個點的子樹中與它距離小於等於l的點有多少個。

輸入輸出格式

輸入格式:

  • Line 1: 2 integers, N and L (1 <= N <= 200,000, 1 <= L <= 10^18)

  • Lines 2..N: The ith line contains two integers p_i and l_i. p_i (1 <= p_i < i) is the first pasture on the shortest path between pasture i and the barn, and l_i (1 <= l_i <= 10^12) is the length of that path.

輸出格式:

  • Lines 1..N: One number per line, the number on line i is the number pastures that can be reached from pasture i by taking roads that lead strictly farther away from the barn (pasture 1) whose total length does not exceed L.

輸入輸出樣例

輸入樣例#1:

4 5
1 4
2 3
1 5

輸出樣例#1:

3
2
1
1

說明

Cows from pasture 1 can hide at pastures 1, 2, and 4.

Cows from pasture 2 can hide at pastures 2 and 3.

Pasture 3 and 4 are as far from the barn as possible, and the cows can hide there.

Solution

這道題做法也是千千萬萬...倍增+差分/左偏樹/主席樹/...

蒟蒻我寫的主席樹

左偏樹只寫過一道題,所以對這道題思路不是很熟,稍微講一下倍增+差分的思路吧,我們要找到一個點的子樹中距離小於等於L的節點的個數,最樸素的做法就是暴力查詢,找到一個打標記,但是這樣的優化空間很大,尋找我們可以用倍增優化,標記可以差分,時間複雜度\(O(nlogn)\)


下面是主席樹的思路,我們要尋找一個節點\(u\)子樹中距離小於等於L的節點\(v\)的個數,即需要滿足這樣的條件:\(dis[v]-dis[u]<=L\to dis[u]>=dis[v]+L\)

問題就轉化成了求子樹內小於一個值的個數,主席樹啊

對權值建樹....

注意:dis[v]+L不一定在原序列中出現過,所以我們用upper_bound,找的時候就變成嚴格<才統計答案,最後為了一定能找到,我們在序列的末尾加一個inf

Code

#include<bits/stdc++.h>
#define mid ((l+r)>>1) 
#define in(i) (i=read())
#define lol long long 
using namespace std;

const lol N=2e5+10,inf=2e15;

lol read()
{
    lol ans=0,f=1; char i=getchar();
    while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();} 
    while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0',i=getchar();
    return ans*f; 
}

lol n,m,cur,tot,dfscnt,L;
lol head[N],nex[N<<1],to[N<<1],w[N<<1];
lol a[N],b[N],inc[N],ouc[N],rt[N];

struct Chair_Tree {
    lol l,r,v;
}t[N<<5];

void add(lol a,lol b,lol c) {
    to[++cur]=b,nex[cur]=head[a],w[cur]=c,head[a]=cur;
    to[++cur]=a,nex[cur]=head[b],w[cur]=c,head[b]=cur;
} 

void insert(lol &u,lol l,lol r,lol pre,lol p) {
    t[u=++tot]=t[pre], t[u].v++;
    if(l==r) return;
    if(p<=mid) insert(t[u].l,l,mid,t[pre].l,p);
    else insert(t[u].r,mid+1,r,t[pre].r,p);
}

lol query(lol u,lol v,lol l,lol r,lol k) {
    if(r<k) return t[v].v-t[u].v;
    if(l>=k) return 0;
    if(k<=mid) return query(t[u].l,t[v].l,l,mid,k);
    else return query(t[u].r,t[v].r,mid+1,r,k)+t[t[v].l].v-t[t[u].l].v;
}

void init(lol u,lol fa,lol now) {
    inc[u]=++dfscnt, a[++m]=b[m]=now;
    for (lol i=head[u];i;i=nex[i]) {
        if(to[i]==fa) continue;
        init(to[i],u,now+w[i]);
    }ouc[u]=dfscnt;
}

int main()
{
    in(n), in(L);
    for (lol i=2,f,c;i<=n;i++)
        in(f), in(c), add(i,f,c);
    init(1,0,0);
    sort(b+1,b+1+m); m=unique(b+1,b+1+m)-b-1;
    for (lol i=1;i<=n;i++) {
        lol p=lower_bound(b+1,b+1+m,a[i])-b;
        insert(rt[i],1,m,rt[i-1],p);
    }
    b[m+1]=inf;
    for (lol i=1,ans;i<=n;i++) {
        lol k=upper_bound(b+1,b+2+m,a[inc[i]]+L)-b;
        ans=query(rt[inc[i]-1],rt[ouc[i]],1,m,k);
        printf("%lld\n",ans);
    }
}